vic
Hey!,
I’m defining a macro that is expected to be called with a variable (provided by the user from their scope) and assign to it. I was expecting the anonymous function generated by the code bellow to be able to assign some value into this variable. I was thinking that since I’m unquoting the var explicitly that would make it unambiguous what variable I’m referring to (the user provided one) and not a new variable inside a new function scope.
May you help me get this right?
Thanks, :)`
defmodule FooTest do
use ExUnit.Case
defmacro foo(var) do
quote do
fn value ->
old = unquote(var)
unquote(var) = value
old
end
end
end
test "change the given var" do
x = 1
assert 1 == foo(x).(99)
assert x == 99 # Fails here, as x is still 1
end
end
Edit: Added another test without a macro, but in this case I understand the x inside the anonymous function might actually be fresh-variable on the anon-fun-scope. Again, I’d expect the macro case to work as I’m not talking about a new x but the original user provided one.
test "change the given var" do
x = 1
assert 1 == (fn y -> x = y; x end).(99)
assert x == 99 # also fails, but that's ok.
end
Trending in Questions
Other Trending Topics
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
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
NobbZ
I’m on the bus right now and only have my mobile, but if I understand you correctly it’s
var!/2you are searching for.I can’t give you an example of how to use it, as I’m on the bus.
On the other hand side you should try to redefine your requirements and find a way to do your job without var!/2.
vic
Hey @NobbZ
Oh yes, I already know about
var!/2and know it can be used to affect the context, like:But in my original
foomacro it’s not what I want to use. I want thefoomacro to take the variable it should work with, instead of relying on var!/2 (likebardoes).The following for example works:
So, just like
foo,baztakes the variable that will be assigned to. The only difference betweenfoo(which is the one I really want) andbazis thatfoocreates an anonymous function, and the variable is unquoted for assignment inside of it. So I guess it has to be something definitely related to anon-functions. It’s just that I’d expect myfoomacro to just work, as I’m not introducing (nor want) a new variable, I’m just trying to use the one provided to me (like inbaz).Nicd
What you want (with the anonymous function) cannot work, because data is immutable in Elixir. The function can rebind the variable in its own scope to something else but outside the function the variable value is still unchanged. You cannot change it from inside the function.
vic
So, investigating it further, I’ve just wrapped
foo(which is now a function) inblajust to inspect the whole generated code. Looking at the output, the variable inside the anon-function offoobeing set is just the one given to it bybla.But I’m sure I’m missing something obvious and just need some sleep haha. No clue.
And here’s the output:
See that the
{:x, [counter: 1], FooTest}variable is correctly being used in the anonymous function insidefoo.vic
Oh, so you can re-bind a variable only on it’s own function scope. So what’s happening in my code, am I introducing just another
x(with same module contextFooTest, and even the same:counter) but they are actually different variables?Nicd
If I’m reading this right, what your code boils down to after the macro expansion is
So in your function you are rebinding the variable
varto something but when the function is over that context will be lost and only the returned value will remain. So you can see that it’s not possible to change the binding ofxfrom inside the function.vic
No, actually it’s:
But even when the inspected code prints that my
xvariable is the same in the whole AST, it’s not actually being the same at execution time. So I guess, just like you said, it’s just anotherxinside the anonymous function. (Even if I set the module context and even the variable counter, haha)Hm…
vic
Yeah, this has nothing to do with macros. It’s just the way var scope works (every function has its own scope). So even if you can re-assign a variable, it’s only possible inside the same function scope. An anonymous function, even when it creates a closure, can read from them, but if some var is assigned (like I was trying to do) it’s a completely new variable inside the inner function scope.
vic
So when you write in Elixir:
I’m just guessing (havent looked at the compiler) that they are actually two different erlang variables (as in erlang you cant re-assign to previously defined variables. It’s just that the compiler keeps track of which is the last
afor subsequent expressions I guess.vic
So, all the code I wrote was just meta-code for the examples in the initial post, haha. Just trying to realize what was happening with that
xvariable.Thanks both @NobbZ, @Nicd for reading and replying to my nonsense.
Time for me to get some sleep, otherwise I cant get some pretty obvious stuff