You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Crystal appears to copy Ruby's ability to define a class method outside a definition of that type, by using a type name as the receiver of a def instead of self:
moduleFooenddefFoo.foo1endFoo.foo # => 1
It even works if the target type is unrelated to the current definition scope:
moduleFooendmoduleBardefFoo.foo1endmoduleFoo; end# not a redefinitiondefFoo.foo2endendFoo.foo # => 1Bar::Foo.foo # => 2
I think this is confusing, as the those targets depend on whether Bar::Foo has been defined prior to the def, so I would like the compiler to reject the second case at least. There is less ambiguity in the first case because those type lookups always start from the top level.
Crystal itself uses the top-level defs extensively in src/json/from_json.cr and src/yaml/from_yaml.cr, and also for the Spec module. The only non-top-level defs already refer to the enclosing type:
Is there a valid use case for redefining another class's method within another type scope? (e.g., first def in Bar). To me it sounds like we can keep the top-level re-definition (which saves you from module Foo; def foo; ...; end; end), and consider the second case as a re-definition of Bar::Foo.
One application I recently found is being able to do this without #8422:
require"json"# okay, `NoReturn.from_json` will deserialize to a "value" of type NoReturndefNoReturn.new(pull : JSON::PullParser) : NoReturn
pull.raise "Cannot deserialize to NoReturn"end
This then allows one to write:
structFooincludeJSON::Serializable# okay, this is a formally correct way to specify that `x` must be an empty arraygetter x : Array(NoReturn)
endFoo.from_json %({"x":[]})# => Foo(@x=[])Foo.from_json %({"x":[1]})# Cannot deserialize to NoReturn at line 1, column 8 (JSON::SerializableError)
The alternative, which might look even odder to some eyes, is:
aliasNoReturnClass=NoReturn.class
classNoReturnClassdefnew(pull : JSON::PullParser)
pull.raise "Cannot deserialize to NoReturn"endend
Crystal appears to copy Ruby's ability to define a class method outside a definition of that type, by using a type name as the receiver of a def instead of
self
:It even works if the target type is unrelated to the current definition scope:
I think this is confusing, as the those targets depend on whether
Bar::Foo
has been defined prior to the def, so I would like the compiler to reject the second case at least. There is less ambiguity in the first case because those type lookups always start from the top level.Crystal itself uses the top-level defs extensively in
src/json/from_json.cr
andsrc/yaml/from_yaml.cr
, and also for theSpec
module. The only non-top-level defs already refer to the enclosing type:crystal/src/float.cr
Lines 262 to 270 in 9e52dd6
The text was updated successfully, but these errors were encountered: