Right now as looks like this:
exp as Type
It's the only expression (I think) that doesn't look like a method call. Every other "special" expression (is_a?, responds_to?, sizeof, pointerof, uninitialized, include, typeof, nil?) looks like a method.
What if we change it to:
exp.as(Type) # or just exp.as Type
Pros:
(exp as Type).method vs. exp.as(Type).method. Parens at the beginning sometimes means I have to go back, add them, and then go forward when typing. The last form is also maybe easier to read.&.: exp.method &.as(Int32) vs. exp.method { |x| x as Int32 }Cons:
As a bonus, we can later add a similar special expression, exp.as?(T), that returns exp as T if the expression is of type T, or returns nil otherwise. So one can do:
foo.bar.baz.as?(Int32).try &.abs
instead of being forced to use a local variable:
tmp = foo.bar.baz
tmp.is_a?(Int32) ? tmp.abs : nil
This is actually inspired by Kotlin's as?.
@BlaXpirit @lbguilherme Why the downvotes? I'm interested in good arguments against this change.
@asterite: I don't really have any strong point against it, just a matter of style and syntax. Doing it as an operator looks odd to me, specially because of the dot there.
what about change x = [] of Int32 to x = [].of(Int32)
@kostya Such change would definitely make writing Ruby compatible code easier (#593), because it is possible to monkey patch the of and as methods in some compatibility layer.
An alternative syntax might be probably x = [].as(Array(Int32)), which also gets rid of theof keyword. Still this means more typing, which is a bad thing.
@ssvb these are not methods, they're, hmm, "pseudo methods" - keywords in practice. The change doesn't make it a method, it simply uses dot-method syntax.
If it were method-looking, I'd expect [Int32, Int16].each {|k| p 3.as(k)} to work, which I don't think it does currently.
@will, this does not work:
[Int32, Int16].map {|k| p 3.is_a?(k)}
@kostya It's true that of is similar to as, in that it has space around it. However, of is only useful for array/hash literals, so it's not a general thing. There's also no &.of(...) or similar. It's true that for chaining you have to do ([] of Int32).method, but the only places I found that are in specs.
And it's true that as and is_a? are special in that they accept an explicit type (they can't accept a varaible). However, at least for is_a?, we could make it work in those cases, so having it look like a method isn't that strange.
Syntax sugar is a part of any language, so in this case this is a sugar of Crystal. If we are going to make everything looks like a method call, then probably let's do calculation only this way:
1.+(2)
:smile:
I like the consistency, I just want to give an example why doing it with as can be a bad idea.
as can be used in a huge variety of contexts and it can be a part of many different existing DSL-s, which can't be said for words like
responds_to?, sizeof, pointerof, uninitialized, include, typeof, nil?
(e.g. in a parser DSL like here: lingo )
Conflating methods and operators seems perilous: confuses new developers and makes the learning curve and documentation burden even higher.
Syntax like Go's type assertion style would be simpler, less confusing and easier to explain and document:
exp.(Type).method or exp.Type.method
And much easier to read quickly.
@steakknife But how are methods different from operators? Both takes data in and produce data out, possibly with a different type. as can pretty much be a method, or at least look like a method. Making these things look like methods means less things to learn, not more. They use the same familiar method calling syntax.
@steakknife, aside from the method/operator confusion (as is neither): that syntax idea is very interesting!
Most helpful comment
I like the consistency, I just want to give an example why doing it with
ascan be a bad idea.ascan be used in a huge variety of contexts and it can be a part of many different existing DSL-s, which can't be said for words like(e.g. in a parser DSL like here: lingo )