> Because it is not meant to be a guard—it cannot further empower a function head and pattern match and be optimized and/or inlined by the compiler. Simple as that.
First of all, that's not an explanation, that is handwaving. The real explanation is that URI.char_reserved? could be rewritten using defguard, because it only uses `in`[0]. An arbitrary choice (whether conscious or unconscious) was taken, that this particular standard library function is not allowed to be used in guards. But there is no good reason for it.
Secondly, are you claiming that it is not useful to be able to use URI.char_reserved?/1 in a guard? That's obviously bullshit.
Finally: The real reason why some things can be used in guards and other can't, is that Elixir must be able to guarantee that no side-effects happen while evaluating a guard[1]. This is a good reason (a good follow-up question is, "why must guards be side-effect free?") and something you can use to form a mental model of which functions you can use in guards and which you cannot, but it is not described anywhere in the Elixir documentation. It's not an easy thing to form a mental model around, but it can be done.
To be fair, I think this is a shortcoming in Erlang as well. It would be better to be able to look at the type of a function and be able to tell whether I can use it in a guard or not. Or just allow all functions to be used in guards, such as in Haskell.
I have read this whole subthread and it is quite interesting because it is clear everyone involved knows what they are talking about, but speaking past each other. :)
I agree with you that you have to build a mental model and you have to memorize (or consult) which guards are available, but arguably the `is_foo` vs `foo?` distinction here is a positive one, because it only takes a glance to know if it is a guard or not (and the majority of guards have the `is_*` prefix so you have to memorize fewer).
You are correct URI.char_reserved? could have been a guard - but that should not be a confusion point for a user of the library - it is clear it is not a guard function. The confusion only arises as a contributor once you read the source as to why a certain choice was made (in this particular case, char_reserved? was written before defguard existed, but even if I wrote it today I am not sure I would consider the possibility users would invoke it in guards).
Btw, I know you know this. I just hope this clarifies the whole discussion a bit for others!
The goalposts of this conversation seem to keep moving. It sounds like you don’t like some of Elixir’s choices. That’s fair.
I wasn’t hand waving, I was simply summarizing guards in general. We’ve both provided the same explanation regarding why some things can or cannot be guards —you’ve linked to Erlang’s discussion of guards; I’ve linked to Elixir’s. So we both understand guards and their limitations.
I’m not terribly interested in arguing about what should or shouldn’t be “guard-worthy”. The built-in guards don’t strike me as arbitrary choices, but as intentional choices as part of designing core language features—that’s all in Kernel, on which everything else depends.
The URI module, while a great part of the stdlib, is not core language guard material. I can say that in 7 years, I’ve never needed or wanted a built-in guard to check if a character was a reserved URI char—but I can believe some problem spaces might have use for enhanced guards. Why, I’ve written my own for having more readable and shorter guards for things like empty lists, maps, and more. The ability to compose those from core language guards and features is one of the many things that makes Elixir a great language for my use cases.
First of all, that's not an explanation, that is handwaving. The real explanation is that URI.char_reserved? could be rewritten using defguard, because it only uses `in`[0]. An arbitrary choice (whether conscious or unconscious) was taken, that this particular standard library function is not allowed to be used in guards. But there is no good reason for it.
Secondly, are you claiming that it is not useful to be able to use URI.char_reserved?/1 in a guard? That's obviously bullshit.
Finally: The real reason why some things can be used in guards and other can't, is that Elixir must be able to guarantee that no side-effects happen while evaluating a guard[1]. This is a good reason (a good follow-up question is, "why must guards be side-effect free?") and something you can use to form a mental model of which functions you can use in guards and which you cannot, but it is not described anywhere in the Elixir documentation. It's not an easy thing to form a mental model around, but it can be done.
To be fair, I think this is a shortcoming in Erlang as well. It would be better to be able to look at the type of a function and be able to tell whether I can use it in a guard or not. Or just allow all functions to be used in guards, such as in Haskell.
0: https://gist.github.com/Munksgaard/ccac61310651d3402571506e4...
1: https://www.erlang.org/docs/22/reference_manual/expressions#...