Open faultyserver opened 6 years ago
In Crystal, you can define methods using things like this, like this:
put_line
def put_line(line=__LINE__)
puts "Called from line #{line}"
end
Which outputs: Called from line 1
(https://play.crystal-lang.org/#/r/3xak).
Is this not possible in Myst? If it is not, making it so, seems sufficient, and much more effective, to me.
I mean, this callinfo
proposed is just a helper for defining methods like in the example, if this callinfo
needs to be set for every call (which it has if I am not mistaken), I think we should be very careful.
Take a recursive method like factorial
, if the method calls itself a thousand times, wouldn't the stack have a thousand and one callinfo
s? factorial
doesn't even need any callinfo.
I have by no means any proper proof that this will have a practical effect on performance, but I think that we must be careful about this kind of thing, and that there is no need for calls to contain this kind of callinfo without it being explicitly stated like in the examlpe.
Maybe some sort of tag however can make this callinfo
avaible, like
@[WithCallInfo]
def put_line
STDOUT.puts(callinfo[:line])
end
(This example was just the first thing that popped into mind, and I have not thought properly about it at all. And I know we have no such attributes currently) EDIT: Given some thought; bad idea XD
I would really rather avoid re-using __LINE__
and __FILE__
, since it puts a condition on what they mean depending on the context (i.e., it becomes "__LINE__
is replaced by the line number that the token appears on, except when it's in a method definition, where it means the caller's line number"). I don't like that overload, and it would be the only overload like that in the entire language.
As for how it gets set, it should be possible to calculate the value on the fly, without any need for a stack. Even if there was, it would probably be part of the callstack
, which already tracks every Call that gets made, so the overhead would be pretty minimal.
__LINE__
is replaced by the line number that the token appears on, except when it's in a method definition, where it means the caller's line number.
I have always seen it as: the token appears on the line number its called from, even though not passed, as it is the default parameter, like this:
foo (line:__LINE__) # Line 1
# ^^^^^^^^ Token appears here
foo#(line:__LINE__) Line 3
# ^^^^^^^^ And here, at least that is how I have understood default parameter values
def foo(line=__LINE__); ... ; end
Personally at least, I think having it like that is pretty rational.
But, I agree now, seing how every Node
already has their #location
; not much reason not to have this callinfo
keyword.
Huh, I hadn't seen that description of it before. That's certainly a little bit nicer than what I wrote. I'm still not a huge fan of those semantics, either, cause they are still a special case. For example, if you reference an instance variable as a default value, it still gets evaluated in the context where the method is defined, while __LINE__
is where the method is called.
There's definitely a need for discussion about what default arguments should look like, and maybe there's some nicer solution that will come with that, but for now I'd like to avoid overloading the constant (visually and/or implementation wise).
I'd be down to change callinfo
into something like __CALLER__
to keep the look/feel of the magic constant, though.
Oh god, please not __CALLER__
😄 it’d look absolutely terrible.
callinfo
would be a language-managed variable, similar toself
, that provides some introspective information about the caller of a method. As a language variable,callinfo
would also be added as a new keyword.Having access to meta information about the caller of a method is primarily helpful for debugging and tooling inside of Myst. The most obvious usecases are the
Spec
andAssert
libraries.Most spec libraries provide location information about failing specs to help users locate them quickly and easily. In Myst, this isn't a practical possibility yet, because the library has no way of accessing that location information without requiring the user to pass in
__FILE__
and__LINE__
values for everyit
block.Adding
callinfo
would provide that location information to these modules automatically, without any burden on the user. It would also avoid having conditional semantics for the magic constants, which I've never particularly liked.Semantics
Referencing
callinfo
outside of a method definition will always returnnil
.Inside of a method definition,
callinfo
returns a Map with these entries::file
: the file containing the call to this method.:line
: the line number of the call to this method.:dir
: the directory containing the file with the call to this method.For simplicity, this Map is newly-created every time
callinfo
is invoked. This ensures both "psuedo-immutability", and that the values are accurate for the current call.Example usage
Retrieving the location information of a Call using
callinfo
could look something like this: