Stream: helpdesk (published)

Topic: ✔ Non-polluting `@auto` macro


view this post on Zulip Mosè Giordano (Apr 01 2022 at 19:28):

auto is everyone's favourite (modern) C++ keyword. Now that we have typed globals, it'd be cool to be able to type @auto x = 2 to get the expression x::Int = 2. Probably not much useful here, but it may be useful in cases where the right-hand side has a much more complex type.

I quickly cooked this macro:

macro auto(ex)
    ex.head !== :(=) && throw(ArgumentError("@auto: `$(ex)` is not an assigment expression."))
    return :( x = $(esc(ex.args[2])); $(esc(ex.args[1]))::typeof(x) = x )
end

but it has the issue that it pollutes the current scope with a gensym'ed variable (x in the body of the macro). if you're wondering why doing

x = $(esc(ex.args[2])); $(esc(ex.args[1]))::typeof(x) = x

instead of

$(esc(ex.args[1]))::typeof($(esc(ex.args[2]))) = $(esc(ex.args[2]))

that's to avoid evaluating twice the right-hand side of the assignment expression, which may be costly and/or have side effects.

is there a way to avoid avoid polluting the namespace with the extra name? I thought about doing

let
    x = $(esc(ex.args[2]))
    global $(esc(ex.args[1]))::typeof(x) = x
end

but that wouldn't work in local scope (like inside a function), which would be nice to retain.

I feel like someone else may have done this macro before

view this post on Zulip chriselrod (Apr 01 2022 at 19:35):

What's the problem with polluting the namespace with gensymed variable names?

I'd been meaning to write a version of this macro that walks the following expression, applying the assert to all assignments.
Would be nice to write @auto function, for example.

view this post on Zulip jar (Apr 01 2022 at 20:00):

In Julia I'd like a more specific name than auto since, unlike in C++, the pre-identifier position isn't assumed to be a type. eg @infertype, @infer, ...

view this post on Zulip Mason Protter (Apr 01 2022 at 20:22):

I like @stable

view this post on Zulip Christopher Rowley (Apr 01 2022 at 20:22):

Is

x = foo()
x::typeof(x)

valid Julia (I'm on my phone)?

view this post on Zulip Mason Protter (Apr 01 2022 at 20:22):

Yes, but that's just an assert, not a promise that the type won't change

view this post on Zulip Christopher Rowley (Apr 01 2022 at 20:24):

Or

x = foo()
x::typeof(x) = x

?

view this post on Zulip Mason Protter (Apr 01 2022 at 20:26):

@Mosè Giordano

julia> macro auto(ex)
           ex.head !== :(=) && throw(ArgumentError("@auto: `$(ex)` is not an assigment expression."))
           quote
               local x = $(esc(ex.args[2]))
               $(esc(ex.args[1]))::typeof(x) = x
           end
       end

The local keyword is what you want I think

view this post on Zulip Mosè Giordano (Apr 01 2022 at 21:24):

chriselrod said:

What's the problem with polluting the namespace with gensymed variable names?

it isn't a huge deal, but it's still nice to avoid introducing extra variables if possible at all. I've got bitten by tests in Base which check the number of names before and after calling a macro :smile:

Mason Protter said:

The local keyword is what you want I think

oh yes, that was it, thanks!

view this post on Zulip Notification Bot (Apr 01 2022 at 21:24):

Mosè Giordano has marked this topic as resolved.


Last updated: Nov 22 2024 at 04:41 UTC