String text = ”data type in Elixir”;

i’ve recently gotten annoyed at having to jump between files just to check what that function i’m using will return. VS Code could be of help by using @spec, but frankly that too is pretty dense to read.

i would like this Elixir syntax

%MyStruct{} = my_var = Module.some_function()

to be easily readable like this

MyStruct my_var = Module.some_function()

this is just a readability thing. imagining a large function full of this kind of rows i’d much prefer tha latter syntax. it should reduce load on memory by a lot.

before i jump in to learn macros just to create this thing, i thought i’d ask you guys - is this approach a bad idea? is there something out there already? is there a better approach completely?

First of all, this is pretty hard to do with macros. You’ll need to create context-aware AST traversal function to do this right.

Second, just learn to read specs, they’re not that hard to read, to be honest.

It depends on what you want to achieve. I guess that you’re saying something like “I used to work with static typing, and I’d like to have this in Elixir”, but this is generally a bad approach, since Elixir is dynamically typed language by design.

So, there are a lot of different ways to achieve what you want with dynamic typing. If you want to find errors and typos during development, you can use dialyzer which has integrations with every editor. If you want to find errors at compile-time, you can use dialyzer, gradualizer, eqwalizer, etc and you can write unit-tests of course.

2 Likes

thanks for the answer, but i think you’re missing my point a bit. i’m not trying to create bug free code (which i am totally looking into atm so thanks for suggestions on those, just not what this topic is about), i’m trying to increase readability and reduce memory load.

huh? as far as i can see i just need to rewrite MyStruct my_var = to %MyStruct{} = my_var =, shouldn’t be too hard to reorder some keywords, or what am i missing? yeah i know nothing of macros yet, not sure what you mean by context.

i can read specs easily, that’s not the issue. it takes time, brainpower and memory. probably more for me than others since i have an exceptionally bad memory. i forget the type right after i close the file i was reading it from.

i’ve actually worked with typed languages very little and i’m not a fan. however there are some benefits. like less mental load (in certain situations). this is what i’m trying to achieve.

again, not the topic, but haven’t heard of gradualizer and eqwalizer. i’ll check these out.

There’s two parts to this. There’s the elixir parser, which requires you to write correct elixir syntax. Otherwise it cannot parse the code. Once the code is parsed by the parser (into AST) macros can come in and change their input AST – could be code blowing up when trying to be executed – to some different output AST – which hopefully runs just fine when executed.

MyStruct my_var = isn’t valid elixir syntax – quote do: MyStruct my_var = 1 doesn’t succeed, so there’s nothing a macro could do here.

Not really sure why you’d like this to change the syntax here. If you want the structs be listed why not write %MyStruct{} = my_var = …? That just works and can even help out editor autocomplete.

4 Likes

As far as I can see, as @LostKobrakai said, this cannot be achieved with macros, because it is not valid Elixir syntax. You would have to build a transpiler, but that’s a totally different kind of problem.

I’d suggest using one of the typing solutions proposed. The issue is mostly about familiarity, and it will soon become second nature if you use it a lot.

My personal view is that a syntax like MyStruct my_var = Module.some_function() would lead people to (erroneously) assume that this is a static type check, while %MyStruct{} = ... makes it clear this is a pattern match, which usually is amongst the first concepts learned when approaching Elixir. In fact, in many cases, when needing to access fields in the struct, one would directly do %MyStruct{ my_field: x } = ....

In other words, there is a trade off between ergonomics and consistency/parsimony of the syntax. Some alternative way to express the same construct more concisely might save some keystrokes, but it adds to the cognitive load of having to understand different ways to express the same thing.

1 Like

You might find the built in jinterface package could help meet your needs :smirk:

3 Likes

oh. okay. i guess i misunderstood the whole thing.

it’s just a hassle to write every time. i don’t find autocomplete very helpful. it jumps in sometimes only.

if we were discussing changing the elixir syntac, then yeah, i’d agree. but since we’re talking package, then it’s not a problem. like i like using shorter_maps. doesn’t lead to any problems.

not sure what this is.


all in all i guess i’m going to try out the explicit syntax and see where i end up. atm i feel like it’s noisy and i may end up avoiding it and thus not having a solution at all.

I think you will see over time that there are very few scenarios where this is syntax you would really write. In most cases, you will be invoking these functions, and evaluating them as part of a with or case clause. The %MyStruct{} = my_var = foo() pattern is not necessary. This pattern match will raise a MatchError only if the result of foo() is not a MyStruct struct.

In most real use scenarios, you’re going to want to do some more detailed matching, and probably have an execution path in case that match fails. So more realistic scenarios will look more like this:

case foo() do
 %MyStruct{val: x} when x < 0 ->
   "Value is less than zero"

 _ ->
    "No value found"
end

or

with %MyStruct{} = ms <- foo() do
  OtherModule.process(ms)
else
   result ->
      Logger.error("foo() did not return valid results: #{inspect(result)}.")
end

I agree though that IDEs can be very flaky about actually showing the correct spec / docs in editor. I have many issues with this in IntelliJ, so typically just do a split panel setup with references on the on one half. I miss the robustness of JVM docs / autocomplete.

in business logic you’re right. but in views i often just query the db and go with whatever there is and if something goes wrong an exception is a valid response.

in any case i happened on an AST tutorial and now I understand why this syntax doesn’t make sense. and also since the gradual typing research is actually moving then in the long run i think it’s okay to wait for whatever that is and then think about this whole thing again.

so for now %ThisSyntax{} = will_have_to_do =.

thanks for thinking with me everyone!

1 Like