-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lift the restriction that type variables can only be single letter names #3294
Conversation
Do I understand correctly that this allows type variables of classes to have arbitrary names, but no change for methods? |
@BlaXpirit Yes, this is for type variables of classes and modules, but what do you mean with no change to methods? I guess it means that we don't yet introduce either |
def f(a : SomeType, b : SomeType) It is possible to make any unexisting type become a type variable. This makes little sense, but looking at the title and with no evidence to the contrary, this pull request can be (mis)understood like this. |
Yes, it can be confusing. But no, your example will give an error if you invoke that method and SomeType doesn't exist. For free variables unrelated to type variables you still have to use T, T1, etc. |
We are going back and forth with this. I would say to first decide what to do about #3288 |
I consider this a better alternative to #3288. No ugly syntax is introduced and classes get to introduce long-lived class names, while methods can still easily get away with the short names just for that one method, and compensate with docs if absolutely necessary. |
I think it adds to the confusion.
With this convention I can NEVER confuse a generic type from a type, but if the restriction is lifted, well, there will be NO way to distinguish them without going back to the class definition. |
@ysbaddaden has a very valid point. Perhaps the better solution is simply to promote an idiomatic Crystal de-facto naming scheme of using (completely arbitrarily chosen suggestions here): Or! Even enforce a naming scheme separating type-level and method-level generic symbols! However to do that cleanly, the only way is probably partitioning the letters as in above example - which might be a bit too extreme. On the other hand, with this long-names-allowed syntax, a idiomatic naming convention will also solve the problem, with less restrictions. I've grown very fond of the "duck-lexing" concept prevalent in Crystal. It makes it very easy for a human being to immediately grasp what the intentions and roles of a piece of code and it's identifiers means. Limitations imposed in that regard are good constraints imo (increases clarity of intent). |
@ozra Can you expand on what you mean by "duck-lexing"? |
@RX14 "if it looks like a duck, it probably is a..." B-) |
Conclusion of #3288
With this change, generic type variable can be named however we want. For example:
In the above example, when solving
ArrayWrapper.new([1, 2, 3])
, because the method is invoked on an uninstantiated type (ArrayWrapper(Type)
),Type
acts as a free variable that will take the type of the given Array,Int32
, which makes the returned value be of typeArrayWrapper(Int32)
.When solving
some << 1
,Type
is already bound toInt32
so the call succeeds. This is whysome << "a"
is an error.The last case where we invoke
new
on an instantiated type is similar and will give an error. SoType
can only act as a free variable on uninstantiated generic types.I believe this will make the language a bit better: using T, K and V for collections is OK, but for other non-collection types it might be good to use a more descriptive name instead of just a single letter.
This change still keeps the limitation that types
T
andU
can't be declared at the top-level, though that might change soon.