giddie
I came across this blog post (linked from Elixir Radar) about implementing a match operator that supports guard clauses. And it reminded me that this is a minor annoyance that I come across fairly frequently.
For instance:
# Invalid Syntax
{:ok, x} when is_integer(x) = my_function()
# So I have to do:
{:ok, x} = my_function()
true = is_integer(x)
It seems unlikely that it would just have been overlooked, so I assume there’s some actual reason why the guard syntax isn’t supported. I wonder if anyone knows what it is?
Trending in Discussions
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
New
The obligatory hello world thread!
Who are you and where are you from? :stuck_out_tongue:
New
@chrismccord : I just saw the Extract AGENTS.md from Phoenix.new into phx.new generator commit to the phoenix project.
My initial shotgu...
New
I was working on an Ecto migration and I needed a timestamp. So, for the nth time, I looked up the different data types for timestamps, a...
New
Just a general thread to post chat/news/info relating to AI/ML stuff that may be relevant for Nx now or in the future. Got anything to sh...
New
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
While I am working on the Language Agnostic Code Audit SaaS, which uses MetaAST (spoiler: I am expecting it to be in a good shape for ann...
New
Chat & Discussions>Discussions
Latest on Elixir Forum
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











First 10 of 25 Posts
D4no0
Is that really necessary? I would be horrified to see that kind of code in a complex project.
IMO using typespecs in this case for
my_functionis the way to go, otherwise there is always the option of defining a small private or lambda function for that check.Example of one of those functions:
But I think that this or any other solutions in this ballpark are much worse than using typespecs and catching possible type errors at compile-time.
giddie
Well, typespecs are (very) far from infallible. I use them extensively, and they miss a lot. I like to program defensively, so I use guard clauses a lot to ensure that code fails early. And actually it seems this will work nicely with the upcoming typesystem. Maybe once the compiler actually can guarantee a type, I’ll start moving to compile-time type checking instead of guards.
But actually that’s all by-the-by. The interesting thing here is why guard clauses are not allowed, syntactically, for patterns to the left of match operators.
D4no0
In what regard do they miss? Are we talking about bugs that are currently present in dialyzer or other static analysis tools?
sodapopcan
Regardless of people using them that way, guards are not meant to be type assertions which is why I assume this doesn’t exist. Defensive programming goes against the whole OTP philosophy, really!
You can do this if you want:
Though that is pretty gnarly.
As far as I understand it, they also won’t be strictly necessary for the type system. For example:
<>only works on strings, so the type checker will know what to do. Addingis_binaryguards would be redundant.zachallaun
My opinion: the main purpose of guards is to support branching, not to ensure certain invariants. If I see a match clause error, it’s almost always a bug in that code, not a bug in the caller. If I see a function clause error, it’s almost always a bug in the caller. I also feel like invariants should be checked at boundaries, not scattered throughout the code. Guards on match clauses would, I think, encourage a style of programming that is more difficult to understand and harder to debug. My 2c, opinion could change.
giddie
Really? To me this is an odd claim. The planned Elixir typesystem specifically intends to build on guards as type assertions. Additionally, type assertion in a guard is de-facto useful to help code fail early on unexpected input.
I’d go so far as to say that guards semantically are pattern matches. They offer programmable extension to patterns.
We must be talking at crossed purposes, because I’d say that OTP is pretty much the embodiment of defensive programming.
I think these are the same thing: if you hit a condition for which there is no matching pattern to branch to, you have failed some invariant. In other words, you are using patterns to ensure that data flowing through your functions conform to some expected pattern. We rely on this for fast and efficient failure on unexpected data.
Yeah, I definitely agree with this. But I’d also 100% prefer a pattern match error near some unexpected data over some obscure
key :whatever not found in: nilwaaay down in the stack.D4no0
Absolutely not the case. The “let it crash” philosophy explicitly says that you handle only the expected cases, not all edge cases. The runtime facilitates that extremely well.
As mentioned before, while guards can be used as type assertion, their main role is to do code branching. You start overusing them everywhere to enforce types, you get code that is not readable, has a runtime penalty and loses the value runtime offers. In that case, using a static typed language like golang will bring you more value for your invested time.
giddie
Indeed - I like my code to handle only the expected data, and crash early if it does not conform to those expectations.
Tyson
“Defensive programming” usually refers to the more imperative approach, where you try anticipate potential exceptions (fail if my arguments are null; fail if my values are outside acceptable range).
Contrast that to OTP’s approach of declaratively defining success cases and otherwise “letting it crash” (which it sounds like you are already doing in practice).
Not trying to patronize; seems like just a terminology mismatch.
giddie
Yeah, this is definitely just a difference in where we’re drawing lines for our definitions. When I think about being defensive in my programming style, I’m including the semantics that we get from OTP. So OTP enables a defensive style by providing automated crash-handling mechanisms on unhappy paths. So the defensiveness is largely “outsourced” to the underlying frameworks when I’m coding.
But the way that manifests is that I’m very explicit about what is the happy path. And actually I think specifying exactly how valid data should look is essential to ensure code fails early and is surfaced in a way that makes it easy to solve.
So all of that to say - I absolutely believe that restricting pattern matches to define a strict happy path is important. And I include all forms of patterns and guards in that definition, which brings me back to - why no guards on match operators?