## Where communities thrive

• Join over 1.5M+ people
• Join over 100K+ communities
• Free without limits
##### Activity
• 10:19
• 10:19
straight-shoota edited #12802
• 10:18
straight-shoota synchronize #12802
• 10:17
straight-shoota closed #12806
• 10:17
straight-shoota closed #12810
• 10:08
straight-shoota labeled #6657
• 10:08
straight-shoota unlabeled #6657
• 10:08
straight-shoota unlabeled #6657
• 10:08
straight-shoota closed #6657
• 10:07
straight-shoota labeled #12816
• 10:05
straight-shoota synchronize #12816
• Dec 01 23:53
straight-shoota opened #12816
• Dec 01 23:07
straight-shoota edited #12814
• Dec 01 23:01
straight-shoota synchronize #12814
• Dec 01 22:59
straight-shoota edited #12814
• Dec 01 22:58
straight-shoota edited #12814
• Dec 01 22:58
straight-shoota edited #12814
• Dec 01 22:55
homonoidian opened #12815
• Dec 01 22:55
homonoidian labeled #12815
• Dec 01 22:53
straight-shoota edited #12814
George Dietrich
@Blacksmoke16
eh, i wouldn't worry about it. it's not what you're wanting
mfiano
@mjfiano:matrix.org
[m]
I'm curious how Crystal handles the once-only evaluation problem with macros, but that may be a question for the forums/someone experienced with macros not limited to the Crystal subset of the concept.
George Dietrich
@Blacksmoke16
whats the problem?
mfiano
@mjfiano:matrix.org
[m]
Well, I know very little about Crystal macros but consider you wanted to write a square() macro, that takes 1 argument and multiplies it by itself. Because macros take in AST nodes and output AST nodes, and are expanded before the semantic analysis, such an invocation could be: x = 4; square(x += 1), which would expand into code that basically does (x+=1) * (x+=1), that is, the side effect of incrementing x is evaluated before the second occurence of x is evaluated, giving a wrong answer. I'm not sure if I explained that well enough...
George Dietrich
@Blacksmoke16
ah i see
they're mainly just ways to generate crystal code
mfiano
@mjfiano:matrix.org
[m]
You would expect 25, but would actually get 32
George Dietrich
@Blacksmoke16
this isn't really a good use case for a macro fwiw
mfiano
@mjfiano:matrix.org
[m]
and this was a bad example, only for demonstration purposes. Clearly this should be a method, not a macro :)
Right. Macros are strictly for 2 things only.
George Dietrich
@Blacksmoke16
main benefit of macros is they can generate code based on compile time information. I.e. accessing annotations, all types that inherit from another, or all types that include a module, etc, etc
mfiano
@mjfiano:matrix.org
[m]
Syntactic abstraction and evaluation control.
But this problem comes up a lot in unhygienic macro systems, which CL and Crystal have afaict.
Unhygienic meaning that the the lexical state of the macro expansion can leak into the call site
Usually generating a temporary variable that is guaranteed to be unique is the way to solve this, which I see Crystal can do
George Dietrich
@Blacksmoke16
mhm, those can also be keyed like a hash
which can be quite helpful, when you also bring unique indexes into things
mfiano
@mjfiano:matrix.org
[m]
But as you can see, the once-only macro definition is rather complex to solve such a common issue
Was just wondering if Crystal stood on the shoulder of the giants that have solved it decades ago and included such a thing in the language :)
George Dietrich
@Blacksmoke16
hmm
you can deff run into this as you just saw, like if you did {{x}} * {{x}} but it's also fairly easy to fix
macro square(v)
%v1 = {{v}}
%v1 * %v1
end
macros are deff a more advanced concept, they also aren't as type safe and have quite a few quirks :P
mfiano
@mjfiano:matrix.org
[m]
Oh sure, the solution has an easy fix, but:
• It's not always obvious that there is a problem to solve.
• An automated solution (a macro) is fairly complicated.
• It saves a lot of boilerplate (over time)
mfiano
@mjfiano:matrix.org
[m]
Yeah, macros are advanced and come with a lot of footguns that take years of experience to even realize their existence, especially in Lisp, which has a much more powerful macro system. I will refrain from asking more macro questions until I have had time to see how they map over :)
George Dietrich
@Blacksmoke16
mfiano
@mjfiano:matrix.org
[m]
Oh that issue surprised me...
In Lisp a macro can evaluate at compile time arbitrary pieces of code, even methods that are shared with other macros or runtime code.
I did not know Crystal couldn't do that
George Dietrich
@Blacksmoke16
its a pita
because of that missing piece that you cant define reusable macro code
i.e. that you could use in two separate macros
From IRC (bridge bot)
@FromIRC
<riza> ^
George Dietrich
@Blacksmoke16
you can call a macro from a macro, but that just is moreso nested expansion, which doens't help in this case
From IRC (bridge bot)
@FromIRC
<riza> @Blacksmoke16 what do you mean fresh variables can be "keyed like a hash"
From IRC (bridge bot)
@FromIRC
<riza> hm, I'm not instantly sure how that would be useful, but it's neat to see regardless
George Dietrich
@Blacksmoke16
main use case afaik is if you want to create them in a loop
otherwise if you just did %key, it would be overridden on each iteration
mfiano
@mjfiano:matrix.org
[m]
I see. Also I really like Crystal and I don't mean to sound like a Lisp snob, because there are plenty of them. Lisp is nice, but it's too dynamic for some tasks...which is one thing that makes its macro system powerful. Every phase of the compiler can be invoked by any other phase by the user, which means macros can be expanded at runtime and all that. It's a mind!@#\$, really.
From IRC (bridge bot)
@FromIRC
<riza> Yeah I suppose that could be a useful way to replace https://github.com/mosquito-cr/mosquito/blob/master/src/mosquito/base.cr#L10-L12
<riza> or several places where the finished macro is used
George Dietrich
@Blacksmoke16
use an annotation and iterate over types that have it
then could build a hash literal at build time or whatever you need
or what's that method doing actually?
cant just build a hash of Mosquito::Job.class => Mosquito::Job?
From IRC (bridge bot)
@FromIRC
<riza> Mosquito::Job.class.to_s => Mosquito::Job.class
George Dietrich
@Blacksmoke16
it's been a while since i been in the code, what's this do again?
From IRC (bridge bot)
@FromIRC
<riza> when a job is popped out of redis, it allows the runner to do a lookup in that hash to convert the job name in redis to a reference to the job class