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
{{ message }}
Repository navigation
Incorrect scope after including **::Serializable #6194
require"json"require"json/next/serialization"# (required as I'm using docker nightly; "0.25.0+9")moduleOptionsendclassFooincludeJSON::SerializableincludeOptionsendFoo.new
Yields:
Error in app.cr:9: JSON::Serializable::Options is not a module, it's a annotation
include Options
^~~~~~~
Compiles if Serializable is included last (or if Options is renamed to something not taken):
Yeah I knew that would fix it too, forgot to mention.
I guess I didn't realize that annotations come along with include like that and that the compiler wouldn't skip annotations because I was trying to include.
@straight-shootainclude should include everything in the target module. The problem is that we've created a module designed to be included then used it also for namespacing, which is incorrect.
Think about all the people wanting to include both Serializable and a custom module named Options or Unmapped. The count will be maybe just two or three people in the universe. I think it's better those two or three add a full path there, instead of redesigning the API and ruin it for everyone else (including those two or three).
@straight-shoota if a module is used for namespaces lots of annotation you want them to be included in the namespace to avoid repetition of the full path.
As @RX14 pointed out is a side effect of including Serializable inside Foo that hides the top level Options. User will need to type ::Options.
Whatever other nice name we choose for Options will conflict with some user.
record Link, before : String?, href : String?, anchor : String?, after : String?
Error in 1.cr:1: expanding macro
record Link, before : String?, href : String?, anchor : String?, after : String?
^
...
Link is not a struct, it's a annotation
And also, their usage is only inside @[...], and when fetching via macro method get_attribute, so it's almost like a separate namespace without having one. And, again, this is almost like C# implements annotations.
@Sija What about JSON::Serializable? Does it become Annotations::JSON::Serializable? JSON::Annotations::Serializable?
The first PR I sent with annotations was about having:
moduleMooannotationFooAnnotationendend
And using it like:
@[Moo::Foo]
And retrieving in macros with:
type.get_annotation(Moo::FooAnnotation)
Since annotations are usually created by the same ones consuming them (like JSON::Serializable is), it's the same amount of typing for users (they'd still have to write @[JSON::Field]), and only slightly more inconvenient for authors (having to define annotation FieldAnnottion and doing .get_annotation(JSON::FieldAnnotation)), while also completely avoiding the names clash. And it also makes it obvious that if you see LinkAnnotation in the docs, it's dead obvious that it's an annotation, as opposed to the current Link, Flags, Primitive, and other top-level annotations.
And this is proven to work, it's how C# implements it (kind of).
I'll just leave this idea here. You can discuss other alternatives, and eventually do a change if it's needed 👍
Reacted by Sijawusz Pur Rahnama and Johannes Müller
What about annotation Field and .get_annotation(JSON::Field) being rewritten to annotation FieldAnnotation and .get_annoation(JSON::FieldAnnotation) automatically by the compiler? It would be fairly straightforward, and shouldn't lead to many surprises while keeping the short names.
I still don't like it because it's magic and a hack. If we're going to jump through all these hoops, why not actually have a separate namespace for annotations.
And implementing this doesn't solve the problem, because JSON::Serializable contains other modules (JSON::Serializable::Strict) as well as other annotations, which will conflict in exactly the same way as annotations. In fact it will be worse, because they will be included by include and actually work, silently possibly accidentally adding features to your class.
The weird part of Annotation suffix is that either
a) the declaration is annotation FooAnnotation and ussed as foo @[Foo] leaving references in macros/code as FooAnnotation since that is the name of the constant.
or
b) the declaration is annotation Foo and ussed as foo @[Foo] and leaving references in macros/code as FooAnnotation, making it more implicit but harder to understand at a first glance and will obviously clash with FooAnnotation constant.
I'm ok with going through option b. The only one that should care about that is the developer coding the effect of the annotation. So it's easy to point in the documentation/guide. It helps for better annotation name that won't clash with other constants.
I guess as long as it is used as @[Foo], calling the annotation definition Foo (a) or FooAnnotation (b) makes no big difference. Both cases can work and mostly bother annotation developers. It doesn't really matter IMHO. Docs for users can refer to the name transparently.
(a) it's like it's done in C# because they are classes. But here they word annotation is already stated. That is way I am more in favor of (b). I am not against (a) though. The whole thing is reducing the clashing which both do.
I actually think the current behaviour is fine. It's no use to open an issue and complain about every little detail in the language. The solution was given (use ::Options). Otherwise the language will never settle.
IMO the annotations should not be part of the user-accessible type system.
As they can only be used in @[..] and macro's get_annotation(..), it makes no sense to make them conflict with other types/constants.
Activity
kostya commentedon Jun 14, 2018
this is because exist annotation
JSON::Serializable::Optionsit conflict with your module, try:z64 commentedon Jun 14, 2018
Yeah I knew that would fix it too, forgot to mention.
I guess I didn't realize that annotations come along with
includelike that and that the compiler wouldn't skip annotations because I was trying toinclude.RX14 commentedon Jun 14, 2018
Feels to me like we shouldn't be including stuff into people's classes when they include
JSON::Serializable.Perhaps a rename to
JSON::SerializableOptionsand similar for the other misc modules and annotations underJSON::Serializable.straight-shoota commentedon Jun 14, 2018
@RX14 I'd question if annotations should be included into other namespaces at all...? I can't think of a use case for this.
straight-shoota commentedon Jun 14, 2018
But yes, removing
Optionsfrom the includeableJSON::Serializablenamespace would be a quick fix that doesn't need to change the compiler.JSON::Serializable::StrictandJSON::Serializable::Unmappedsimilarly shouldn't be duplicated into namespaces whereJSON::Serializableis included.asterite commentedon Jun 14, 2018
Well, if annotations would have been named
OptionAnnotationwe woudn't be having this discussion... 🙄(however, it of course can happen with any other type, not just annotations)
Just learn to live with these deficiencies of the language, they are not a big deal.
kostya commentedon Jun 14, 2018
Yes, this is just as any other modules conflicts. I think this is ok, and not even related to annotations, it happens from time to time.
RX14 commentedon Jun 14, 2018
@straight-shoota
includeshould include everything in the target module. The problem is that we've created a module designed to be included then used it also for namespacing, which is incorrect.straight-shoota commentedon Jun 15, 2018
How about we put
Options,StrictandUnmappedin a new moduleJSON::Serialization? Which doesn't do anything else, it's just a namespace.kostya commentedon Jun 15, 2018
this would look weird:
asterite commentedon Jun 15, 2018
Think about all the people wanting to include both Serializable and a custom module named Options or Unmapped. The count will be maybe just two or three people in the universe. I think it's better those two or three add a full path there, instead of redesigning the API and ruin it for everyone else (including those two or three).
bcardiff commentedon Jun 15, 2018
I neither there is much to do here.
@straight-shoota if a module is used for namespaces lots of annotation you want them to be included in the namespace to avoid repetition of the full path.
As @RX14 pointed out is a side effect of including
SerializableinsideFoothat hides the top levelOptions. User will need to type::Options.Whatever other nice name we choose for
Optionswill conflict with some user.kostya commentedon Jun 15, 2018
this is worse conflict, btw:
asterite commentedon Jun 15, 2018
Vote to make annotation names end with a mandatory Annotation suffix? 👍
kostya commentedon Jun 15, 2018
may be Annotation suffix not bad, because defining annotations expect to be quite rare.
asterite commentedon Jun 15, 2018
And also, their usage is only inside
@[...], and when fetching via macro methodget_attribute, so it's almost like a separate namespace without having one. And, again, this is almost like C# implements annotations.Sija commentedon Jun 15, 2018
@asterite
Annotations::Linksounds not that bad too + it's a single namespace for allAnnotations.asterite commentedon Jun 15, 2018
@Sija What about
JSON::Serializable? Does it becomeAnnotations::JSON::Serializable?JSON::Annotations::Serializable?The first PR I sent with annotations was about having:
And using it like:
And retrieving in macros with:
Since annotations are usually created by the same ones consuming them (like
JSON::Serializableis), it's the same amount of typing for users (they'd still have to write@[JSON::Field]), and only slightly more inconvenient for authors (having to defineannotation FieldAnnottionand doing.get_annotation(JSON::FieldAnnotation)), while also completely avoiding the names clash. And it also makes it obvious that if you seeLinkAnnotationin the docs, it's dead obvious that it's an annotation, as opposed to the currentLink,Flags,Primitive, and other top-level annotations.And this is proven to work, it's how C# implements it (kind of).
I'll just leave this idea here. You can discuss other alternatives, and eventually do a change if it's needed 👍
straight-shoota commentedon Jun 16, 2018
What about
annotation Fieldand.get_annotation(JSON::Field)being rewritten toannotation FieldAnnotationand.get_annoation(JSON::FieldAnnotation)automatically by the compiler? It would be fairly straightforward, and shouldn't lead to many surprises while keeping the short names.RX14 commentedon Jun 16, 2018
I still don't like it because it's magic and a hack. If we're going to jump through all these hoops, why not actually have a separate namespace for annotations.
And implementing this doesn't solve the problem, because
JSON::Serializablecontains other modules (JSON::Serializable::Strict) as well as other annotations, which will conflict in exactly the same way as annotations. In fact it will be worse, because they will be included byincludeand actually work, silently possibly accidentally adding features to your class.See: https://carc.in/#/r/4b0v
bcardiff commentedon Jun 21, 2018
The weird part of Annotation suffix is that either
a) the declaration is
annotation FooAnnotationand ussed as foo@[Foo]leaving references in macros/code asFooAnnotationsince that is the name of the constant.or
b) the declaration is
annotation Fooand ussed as foo@[Foo]and leaving references in macros/code asFooAnnotation, making it more implicit but harder to understand at a first glance and will obviously clash with FooAnnotation constant.I'm ok with going through option b. The only one that should care about that is the developer coding the effect of the annotation. So it's easy to point in the documentation/guide. It helps for better annotation name that won't clash with other constants.
asterite commentedon Jun 21, 2018
I think a is better. It's how it's done in C#
straight-shoota commentedon Jun 21, 2018
I guess as long as it is used as
@[Foo], calling the annotation definitionFoo(a) orFooAnnotation(b) makes no big difference. Both cases can work and mostly bother annotation developers. It doesn't really matter IMHO. Docs for users can refer to the name transparently.bcardiff commentedon Jun 21, 2018
(a) it's like it's done in C# because they are classes. But here they word annotation is already stated. That is way I am more in favor of (b). I am not against (a) though. The whole thing is reducing the clashing which both do.
asterite commentedon Jun 21, 2018
I actually think the current behaviour is fine. It's no use to open an issue and complain about every little detail in the language. The solution was given (use
::Options). Otherwise the language will never settle.bew commentedon Nov 1, 2018
@asterite I disagree
IMO the annotations should not be part of the user-accessible type system.
As they can only be used in
@[..]and macro'sget_annotation(..), it makes no sense to make them conflict with other types/constants.