Skip to content

count_until: ensure is_integer when raising argument error#15030

Merged
josevalim merged 1 commit into
elixir-lang:mainfrom
novaugust:me/count-until-is-integer
Dec 31, 2025
Merged

count_until: ensure is_integer when raising argument error#15030
josevalim merged 1 commit into
elixir-lang:mainfrom
novaugust:me/count-until-is-integer

Conversation

@novaugust
Copy link
Copy Markdown
Contributor

@novaugust novaugust commented Dec 30, 2025

adds when is_integer(limit) to the Enum.count_until argument errors from #15029, making sure FunctionClauseError is still raised for non integer limits

@davydog187
Copy link
Copy Markdown
Contributor

IMO FunctionClauseError is internal-facing, and ArgumentError is a better external facing exception for consumers of the API

@zachdaniel
Copy link
Copy Markdown
Contributor

yeah, I'd prefer a fallback raising an ArgumentError when its not an integer, or a clause at the top matching on non-integers not is_integer raising an ArgumentError

@novaugust
Copy link
Copy Markdown
Contributor Author

As is, you'll get neither when a map is passed as the second arg eh? Needs an inspect in the error message if that's the intention

@novaugust
Copy link
Copy Markdown
Contributor Author

IMO FunctionClauseError is internal-facing, and ArgumentError is a better external facing exception for consumers of the API

that's not currently a convention i see in elixir, and to zach's point would involve adding a whole lot of final function clauses and when not is_... to existing ones to become the convention. FunctionClauseError is normal and fine when passed a whacky arg (Enum.count_until([], :whoops), especially since the error includes the patterned heads.

@josevalim
Copy link
Copy Markdown
Member

We typically don’t raise argument errors when the value is outside the domain of the function. So if you pass a list as count, it should be a function clause error. Plus the type system can infer proper types in those cases, if you accept the argument and then raise, it cannot.

@josevalim josevalim merged commit a077a6e into elixir-lang:main Dec 31, 2025
11 checks passed
@josevalim
Copy link
Copy Markdown
Member

💚 💙 💜 💛 ❤️

@novaugust novaugust deleted the me/count-until-is-integer branch December 31, 2025 14:57
@zachdaniel
Copy link
Copy Markdown
Contributor

Plus the type system can infer proper types in those cases, if you accept the argument and then raise, it cannot.

This is pretty interesting. Is there some way we could support this? What you're saying makes sense, but there are many cases when building libraries where we solve DX paper cuts with better error messages.

def function(integer, opts \\ [])

def function(integer, opts) when is_list(integer) do
  raise ArgumentError, "Looks like you tried to pass options in ..."
end

That is a bad/contrived example that maybe should just warrant a function clause error. I'm wondering if functions that literally do nothing but raise an argument error could be considered as non-accepted inputs?


In the end, I realized that you're right the type system just makes it not make sense. You'd get a warning at compile time and so should theoretically never hit the runtime error. It does make me think that there could be some light regression on DX in some ways because we can't "steer" type system error messaging, you just are going to have to decipher the signature or read the docs/examples. A part of me wonders if a function clause with a raise TypeError, .... could make sense, or some other way to improve DX of people as they code and are using commonly incorrect formulations of code could be devised.

Probably not worth the squeeze. Thanks for coming to my TED talk 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants