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
Implementation of "lonely operator" #2177
Comments
+100 |
You already can do what the "lonely operator" can do: # Ruby
foo&.bar
# Crystal
foo.try &.bar Pros of Ruby's way:
Cons of Ruby's Syntax:
Advantages of Crystal's way:
Disadvantages of Crystal's way:
And because in Crystal we try to avoid nil whenever we can, the usage of |
You really hate implementing syntax, don't you? God forbid people might have to "learn something new". Sheesh.
|
Have you heard about the Law of Demeter? https://en.wikipedia.org/wiki/Law_of_Demeter. If I were to collaborate with you on a project and you wrote that expression I'd urge you to refactor that. Would you seriously concatenate 5 nilables on a single line? Sounds to me the only goal of such a line is to ridicule @asterite's position, which happens to be contrary to you. There are other approaches to deal with situations like that, through more cohesive design in OO and through lifting in FP for example. Sheesh. |
I'm not a fan of the lonely operator, and I hope it won't take off in Ruby land, so I don't have to ask myself what is that lost ampersand. I prefer the Rails way that Crystal implemented. Also it would conflict with Crystal's |
The Law of Demeter is stupid. By that law, you would never call methods of values returned by a method call:
Granted, I'd probably not chain five calls like that, but I might:
That's the thing about fluent interfaces and functional languages: you chain method calls. That's the entire purpose of a functional language. Law of Demeter be damned. |
@stugol I actually like adding syntax, if it's going to have many use cases. That's why we have I'm closing this, we are not going to add the lonely operator. |
There is a beauty in a language to have the minimum set of rules. I won't go all the way to Smalltalk though. As @asterite points, Ruby and Crystal differs on how to deal I share de opinion of @ysbaddaden here also. For a single short line |
So. finally, is there anythin like &. / ?. operator to let us make chains like
or even better, as elvis op in Kotlin. The reason 'learn something new' is not a concern as there are little or no crystal coders (not language developers) that are not ready to learn something new and prefer old an ugly to new and handy... I was about to make my company to switch to crystal and maybe invest a little in this language because I really like it and we have to get rid of Oracle JVM anyway, but some ugly things in this great language makes me rethink. When I was, to get proper impression, porting one if our small libraries from ruby to crystal I got stuck into this and into impossibility to hold references as hash values. So if the maintainer position is "simple to implement syntax" - okay, we'll reconsider scala native, despite of it immaturity. Still, if it is just matter of time and effort to add the neat syntax - we could event try to help :) |
This is all explained above:
if value = foo(arg)
# value can't be nil
end All in all, don't bother much, in practice there aren't much nilable situations in crystal, and even less chained nilables (unlike other languages such as JS). |
Looks like you're trying to simply translate Ruby syntax to Crystal syntax. This could be more or less productive, but it's generally not a good idea. If you're just trying to write Ruby in Crystal syntax, you're wasting a lot of efficiency. Ruby and Crystal are different languages and thus porting code means to als transform concepts. Features like Crystal's type system allow using different solutions, which are most likely easier and more performant than an equivalent Ruby implementation. |
I'm not sure sure what you mean by this? reference types can be used as hash values quite easily - in fact |
Thank you for you answer. I like crystal and would love to battle test it in our family of procudts. In fact yes, I'm not yet get the crystal way, and the languages we are using last years are ruby/coffe/java/scala/c++... So maybe I am wrong. Here is the very typical situation in our code: there are nested classes, unless (address = contract&.transaction&.export_address).nil?
# perform export operation In crysral it is different and yes, I could accept something like: if address = contract.transactional.export
# do the export
What I can think of is ugly superpositinos like if (transactional=contract.transactional) && (address=transactinoal.export_address)
# do something This is, actually, too bad, as it is not only too long and hard to read, it looks like an error, I'd As all we know the code we didn't write is a correct code, so we all love ruby and crystal for its About the references in Hash. We too often deal with Hash as a container for arbitrary data - for example, to pack/unpack to various formats we use Java Thank you very much for your help. |
@sergeych you can do: unless (address = contract.try(&.transaction.try(&.export_address)).nil?
end |
Or probably just: if contract.try &.transaction.try &.export_address
end |
That's another one: contract.try(&.transaction).try(&.export_address) |
Well, this is somewhat better, bu why don't we instead of if adddress = (contract.try &.transactional.try &.export address)
puts "Exporting to #{address}" make it as clean and intuitive as if address = contract?.transactional?.export
puts "Exporting to #{address}" From my experience of 30+ years of coding, the readability and cleanness of the compiled code worth an order of magnitude more than compiler itself source/architecture considerations. This case, actually, it does not look a big deal to add new operator. Wish you integrated the scala parser idea that let code to introduce new operators. |
The problem is largely just that the operator really wouldn't be used that often in idiomatic Crystal code.
This is a great way to make your parser incredibly complex... |
true. well, forget it ;) I have tried many approaches with Crystal, and found how to rewrite our code in an elegant and effective way, and is pleased to admit - the language is an outstanding and promising work. Still, you should agree that each programming language (not counting brainfuck and some student homework) is intended to make writing real-world code easy and pleasant. What means, when the language provides no way to code some typical real-world pattern easily, no idiomatic approach could help. I have shown you the real sample, which often occurs not only in our code, but also in many others - that's why all these ?. &. and ?: are so popular and requested. Even ObjC in its stone age already had a solution for chained nullable calls. Moreover, I and my company write a lot in Scala, where idiomatic way pushes us too to get rid of chained nullable calls, or put them into a for {}, and it was, is, and always be a pain and no idiomatic usage can help to get rid of chained calls. Crystal actually admits it - thats why there is |
Well I mean having |
@sergeych not being able to do that is a current limitation. It's not that we don't want you to do it, it's just that there wasn't enough time to do it. |
The fact that It pushes code to get rid of
Crystal makes me think more about what happens when things fail, and I enjoy that. Hint: the guard pattern is very common in crystal, i.e. raise "foo" unless bar which raises an error if |
Thank you. Bad sample, actually, neede one more level of indirection to illustrate. We never use nil as an error result since C++ exceptions appearance, but we still use it as an absence flag. For example, when we get result from the remote method call, it is handy to check like this: if code = response&.error&.code
raise Umi::Error.new(code) in our case, error block contains more information, but we need only the code. this was handly, though for sure I can live without it some time ;) Thank you very much, all of you who answered. BTW - if it is a limitation, why to close? leave it open and mark help wanted. Who wants it that bad could try to implement ;) |
@sergeych the limitation is Reference in Hash. The lonely operator is not a limitation, it's a choice. Sorry I wasn't clear, I was replying to the last thing you said. |
@sergeych your code still implies Then it's just if error = response.error
raise Umi::Error.new(error.code)
end |
A value being |
AFAIK it is the same as Option in scala so it should be basically the same. And my opinion - and shared by manu of my colleagues - that it is a bad approach. Scala is a great language, maybe the best, but many have left it for Kotlin because its nil processing is much more convenient. If my opinion does not seem valuable to you, ask yourself why in most popular languages this feature exist? See https://en.wikipedia.org/wiki/Safe_navigation_operator - 10 top languages do implement it. Pity you insist crystal should never be as good as other languages are. Well, as you wish. Personally, after recent scala collapse I feel bad about languages where idiomatic concerns prevail the convenience and beauty. |
@sergeych That wikipedia page shows an example for Crystal. There's a way to do it, just not with a syntax you like. |
I was thinking, if we were able to declare a if address = contract.? &.transactional.? &.export
puts "Exporting to #{address}" This is renaming |
That saves exactly two characters but results in a pretty cryptic syntax. |
Yeah indeed it's a bad idea @straight-shoota , just wondering. Even |
@sergeych The semantics already exists in The crystal core team's argument is that the safe navigation operator is uncommon, therefore doesn't deserve such short syntax. This is different to other languages such as scala and kotlin which have less-powerful type systems and less-powerful type inference, where there is no flow typing, no union types, and variables certainly cannot change type in the middle of a function (for example, to discard a Try is only used 502 times in the crystal repository, that is one usage for every three crystal files, or once usage every 400 lines of code. By data, and by my experience with larger crystal codebases, |
Have to praise, &. is definitely an VERY excellent design in Crystal. |
Hello, I found in last ruby version (2.3.0) "lonely operator" implementation. I found it very useful.
Can it be implemented in Crystal?
The text was updated successfully, but these errors were encountered: