Accept only keyword lists in Image.Options.* validators - #220
Merged
Conversation
hlindset
force-pushed
the
fix/options-map-contract
branch
from
July 29, 2026 07:28
0984d21 to
212618f
Compare
hlindset
force-pushed
the
fix/options-map-contract
branch
from
July 29, 2026 07:28
212618f to
ec113ce
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ten
Image.Options.*modules had avalidate_optionsfunction that took an already-validated map and returned it unchanged. The intent was to allow a validated map to be constructed once, and then reused without paying for the validation cost on each call. Benchmarking showed that the performance gain was marginal (see script/results below), so removing the map-taking functions removes potential footguns from public entry points:Blur,ChromaKey,Draw,Embed,Meme,Modulate,Sharpen,Trim,VibranceandVignetteis_listguards toAffineandRotate, which accepted maps via anEnum.reject/2that converted them to keyword listsis_listguards toResizeandThumbnail, which accepted%{}, and raised on any populated map (because reducing over an empty map returns it unchanged)map()from 22 option union types. Seven of those already rejected maps at runtime, so their types were inaccurateImage.Draw.maybe_add_alpha/2: every caller passes a color fromPixel.to_pixel/3, which always returns exactlybands(image)elementsList.wrap/1(it's always a resolved color list now) in the chroma mask pathImage.Draw.maybe_wrap/1, which was just an identity functionPixel.to_pixel/3took over frommaybe_add_alpha/2Breaking changes
Image.Options.*.validate_optionsaccepts keyword lists onlyPassing a map now raises
FunctionClauseError. AffectsBlur,ChromaKey,Draw,Embed,Meme,Modulate,Sharpen,Trim,Vibrance,Vignette,Affine,Rotate,ResizeandThumbnailFunctionClauseErrorImage.blur/2,Image.feather/2,Image.sharpen/2,Image.modulate/2,Image.vignette/2,Image.embed/4,Image.chroma_mask/2,Image.chroma_key/2,Image.Draw.point/4,rect/6,circle/5,line/6,flood/4,mask/5,image/5,smudge/6Enum.reject/2) and now raiseFunctionClauseErrorImage.rotate/3,Image.affine/3,Image.shear/4FunctionClauseErrorImage.resize/3,Image.thumbnail/3!variants of all of the above raise the same errormap()removed from 22 option union type declarationsSpecs referencing e.g.
Image.Options.Blur.blur_options/0no longer permit a map. Seven of the 22 were already inaccurate, rejecting maps at runtimeImage.Options.Meme.validate_options/1is removedImage.Draw.maybe_add_alpha/2is removed@doc false, so it was public but not documentedBenchmark script
Benchmark result
Resolving the color is the biggest cost, so in a tight loop the win comes from hoisting the color resolution and using it directly in the keyword list, not from full prevalidation.