Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @09:35AM
(#33969386)
I'd consider myself a writer more than a developer, but I've been working in Rails for over 15 years, and one of my absolute favourite things is "unless".
Why? Because it allows you to express yourself more elegantly.
The click-bait title is misleading. It's meant to ridicule "unless", but actually achieves the opposite.
If you were to write the title of the post as code, it would be:
unless !ruby_dev
read article
end
That would be a terrible use of "unless"! That should clearly say "if ruby_dev", not "unless !ruby_dev".
But what if you wanted to write an article meant for anyone other than ruby developers?
Which of the following is better?
if !ruby_dev
or
unless ruby_dev
Both work, but I consider the second option more elegant. Just as I wouldn't verbally say "if you're not a ruby developer" rather than "unless you're a ruby developer".
Honestly, I don't see the issue. It's a style matter. Just use it properly. All language can be abused if you try hard enough.
Re:Read this post ‘unless’ you’re not a Ruby developer
by dlkf on Tuesday December 13, 2022 @12:40PM
(#33972496)
There’s a cost-benefit analysis here that you are refusing to do: Of the two variants you’ve posted, the first will click immediately with a generalist dev who doesn’t know Ruby. The second will have them reasoning out loud, and then reaching for the docs to double check that their common-sense intuitions are correct.
This is not a contrived example. I regularly find myself having to read some code in a language in which I am not proficient. Stuff like ’unless’ is such a pointless obstacle in these scenarios.
So ”elegance” doesn’t come free. The cost is a loss of transferable knowledge from other languages. Your intuition is that this cost is low relative to the benefit of ”elegance,” I have the opposite intuition. Why stray from such universal conventions in favour of one person’s subjective aesthetic preference?
Re:Read this post ‘unless’ you’re not a Ruby developer
by dlkf on Tuesday December 13, 2022 @02:55PM
(#33974780)
I never suggested we ”optimize the language around this feature.” I only suggested that it is a higher virtue than some user on HN’s subjective concept of ”elegance.”
What do you think is more important: the speed at which C programmers can navigate your code base, or one person’s subjective idea of ”elegance”?
Re:Read this post ‘unless’ you’re not a Ruby developer
by marcosdumay on Tuesday December 13, 2022 @04:35PM
(#33976202)
"Elegance" can mean many things, some irrelevant, some very important. But the speed at which C programmers can navigate some non-C code is absolutely irrelevant.
Specifically about Ruby, with it's infinite levels of metaprograming and "you can even redefine the meaning of blank space" philosophy, it's not 'unless' that will stop anybody.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @02:06PM
(#33974086)
It is not all about cost-benefit.
You say there is a difficult time transferring knowledge from other languages when they see the `unless`. That's fair.
My response to that is that, to idiomatically think in Ruby is write code that reads well, and `unless` fits that. Every language has an idiomatic way in which one thinks and reasons with the language. While there are principles that can be transferred over across languages, the way to think in that language does not necessarily transfer. The Ruby community has a heavy emphasis on creating embedded DSLs that seems natural enough to written English, and the Ruby community's style guide is written for that.
In contrast to Ruby, Python has idioms that seem to be the inverse of Ruby. The intuitions on what is good, idiomatic Ruby is counter-intuitive in Python. This even extends to the design of Ruby bundler vs. Python virtualenv/pip. As a long time Rubyist, Python rubs me the wrong way (what is intuitive in Python is counter-intuitive in Ruby) until I realized that I used to write that style of code a long time ago with Pascal.
Re:Read this post ‘unless’ you’re not a Ruby developer
by antod on Tuesday December 13, 2022 @04:28PM
(#33976100)
I have a long history of Python and it fits my brain well, but the last 7 or so years have been in Ruby shops. I still struggle with trying to write idiomatic Ruby sad to say.
I do like `unless` in Ruby, but only when it is the one liner form and the exception happens pretty rarely. The multi line form often takes a lot of effort to parse for me if it is more than a very simple expression.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @07:20PM
(#33978290)
Probably the biggest thing is where and what is being encapsulated. Ruby is inspired by Smalltalk. Objects sends messages to each other, as if the objects are autonomous. They can receive a message, but it is within the object’s discretion on how that is interpreted.
Python exposes those methods. What you see is what you get. Classes and objects are not considered as autonomous agents so much as data structures bound with functions that can operate on it.
More controversially than “unless” is Ruby’s way of calling an anonymous function. Almost every other language, if “f” is a function, you can call it with f(). In Ruby, an anonymous function is an object, and you call it by sending a message “.call()”; the shorthand for “call” being “f.()”. Everything is an object.
This trips up even polygots who like Ruby. But if your mind can shift in such a way where that is ever seen intuitive, then you’re probably well on your way to being able to think in Ruby. (Assuming someone _wants_ to think that way).
Re:Read this post ‘unless’ you’re not a Ruby developer
by dlkf on Tuesday December 13, 2022 @04:12PM
(#33975863)
This is a great comment. The language I use most is Python, and I am definitely biased toward its conventions. It's interesting to hear from the other side of the fence.
I want to suggest a slight reframing: instead of saying: "It is not all about cost-benefit," you could say "here is an addition to the 'benefits' column that hasn't been considered yet."
It's a totally reasonable argument; much better than "elegance." This was my main problem: that the critique of `unless` was much more plausible than the defence.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @07:05PM
(#33978154)
I agree that thinking in terms of this as additional benefits is an excellent way of thinking about this.
However, we don’t always make decisions purely on cost vs benefit. Some types of decisions, such as strategic thinking, involves unfair advantages. If cost-benefits are reasoned from a finite space in which one can find the optimal choice, unfair advantages cheats that, and operates on a potentially infinite space with imperfect information.
Not that I am saying Ruby or Python are unfair advantages :-) I’m just saying that cost-benefit is not the only way in which one can decide on something, and may not be appropriate for every situation. Being able to think in a language can potentially change how you think, and framing that as a benefit can be problematic.
I explored Ruby because I wanted to explore eloquence, semantics, and pattern languages (in the Christopher Alexander sense). I spent over ten years on it until I had my fill. Now I am exploring concurrency, reliability, uncertainty, self-healing and distributed systems — Elixir and Kubernetes. And while I still use Ruby in some tooling, it doesn’t give me the joy that Elixir does.
Re:Read this post ‘unless’ you’re not a Ruby developer
by lcnPylGDnU4H9OF on Tuesday December 13, 2022 @01:38PM
(#33973638)
I get your point, though it's also worth pointing out that it doesn't force anything. Admittedly, syntax highlighting will generally help but it's always possible that a skim simply misses the keyword.
Practically speaking, that's not how I know Ruby to be written. The convention I follow is to use `unless` when there is no `else` case and only when there is no negation in the expression.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:12AM
(#33969876)
Interesting! I wouldn't want to argue against your experience.
I do wonder if it's an issue of "unless" being misused? Programmers using it just for fun rather than considering whether it's the best choice in context?
Re:Read this post ‘unless’ you’re not a Ruby developer
by eloisius on Tuesday December 13, 2022 @10:45AM
(#33970347)
I'm a recovering rubyist (actually I still love ruby, just never get to write it anymore). The only times I felt `unless` was truly more readable than `if !something` was when it was used in the conditional suffix form like
Re:Read this post ‘unless’ you’re not a Ruby developer
by captaincaveman on Wednesday December 14, 2022 @11:51AM
(#33986208)
do_something if not already_done?
Problem with so much syntactic sugar is you need to retain/recall the semantics of the vocabulary. As a polyglot programmer who doesn't write much code anymore, it slows me down.
Re:Read this post ‘unless’ you’re not a Ruby developer
by pantulis on Tuesday December 13, 2022 @12:02PM
(#33971706)
This is the poster child use case for "unless", IMHO.
Anything else (at least for me) is more difficult to read, it's probably due to being exposed to all thos other languages that do not have that syntactic construct. Using C syntax conditionals feels more natural to me, but again this is all opinionated.
Re:Read this post ‘unless’ you’re not a Ruby developer
by mathstuf on Tuesday December 13, 2022 @10:56AM
(#33970558)
Same here. I can handle chaining conditions and narrowing things down, but once there's a De Morgan's filter on the thing, there's just too much state to juggle because what's in front of my eyes is not a refresher for what I actually need to remember ("ok, it says `n < 0`…(De Morgan filter)…n is positive" is too much IMO).
That said, I feel it's really down to double+ negation being hard to handle. `if` with a single negation is fine; `unless` is automatically a negation, so you're just off to a bad start on that front. I feel like the only viable use is in a case like Rust's `let … else { diverge }` where anything that fails the condition is guaranteed to diverge (typically, return) and I can just ignore it when reading the overall codeflow. But Ruby mixes that up and does `diverge unless …` which puts the diverging part "up front" and "in the way" for such readings.
Re:Read this post ‘unless’ you’re not a Ruby developer
by areichert on Tuesday December 13, 2022 @12:25PM
(#33972232)
Man, I feel like you hit the nail on the head here... this is definitely the best way I could think to articulate why `unless` throws me off so much.
Weirdly, Ruby was one of the first languages I learned early in my career, and at the time I had no problem with `unless`. But after years of experience with other languages, I similarly feel that `if` statements now trigger the fast pattern matching circuits in my brain, while `unless` makes me do a double-take and basically translate it into `if not`
At first I thought I was just becoming dumber with age, but I like your explanation better :P
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @02:10PM
(#33974146)
In Ruby (and Crystal), I tend to use `unless` for guards at the top of the method, or returns. These are typically `return foo unless baz`.
When I write Elixir, `unless` gets awkward in a functional style of programming, and Elixir has guard clauses and pattern matching. I pretty much never use `unless` in Elixir despite using it in Ruby for years.
Sometimes, I'll add extra methods with a negation in the name itself. So for example
# instead of
return "invalid" unless valid?
return [] if empty?
# I define invalid?() and do
return "invalid" if invalid?
return [] if empty?
Re:Read this post ‘unless’ you’re not a Ruby developer
by layer8 on Tuesday December 13, 2022 @04:12PM
(#33975859)
It works well in cases where you have an operation that consists of a certain sequence of statements, where one of the statements has to be omitted in a particular atypical situation. Instead of having interrupt the sequence with an if, you just tag the particular statement with the omitting condition at the end. That’s also when unless tends to be intuitive, because it suggests an atypical condition.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @06:49PM
(#33978002)
That is usually where I used it too.
When I started writing these as pipeline execution. Then I’ll use a maybe?() instead if the conditional does not need to depend on the result of a previous operation.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hosh on Tuesday December 13, 2022 @02:25PM
(#33974347)
That's a matter of what fits better with the structure of how you think internally, and not necessarily that there is an objectively better way for self-documentation.
For example, I can totally see how imperative-first would mess up people with neurodivergant brains.
Tangent -- Ruby takes a lot of inspiration from Perl.
Re:Read this post ‘unless’ you’re not a Ruby developer
by gnufied on Tuesday December 13, 2022 @12:07PM
(#33971796)
Also as a non-native English speaker, unless always makes me do a double take. It is not a word that naturally translates in my head, but that might just be me.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:05AM
(#33969759)
Only if you definition of elegance is "please express yourself in as convoluted a way as possible, so as to minimize the number of words I need to know."
The truth is there is a balance in all languages. Nearly every word was invented to prevent having to say a string of other words to mean the same thing.
"Unless" is a single word to mean "If not". I consider that elegant.
However, some languages take this too far, in my opinion. German famously has a word for nearly everything. I'm not sure that's elegant, in that it requires learning a far greater number of words.
English has many words that I wouldn't consider elegant, simply because they're uncommon or convoluted. Never use a 10 dollar word when a 5 cent word will do.
So, if, like me and the ruby community, you prefer to optimize for developer happiness, "unless" is an elegant choice.
If you prefer to optimize for peak computing performance, if may be more computationally efficient use "if not".
But, _unless_ you're saying that you never use the word "unless" in everyday language, I think we can agree it's a good word that has good applications. I don't see why that wouldn't be true in programming.
Re:Read this post ‘unless’ you’re not a Ruby developer
by guitarbill on Tuesday December 13, 2022 @12:00PM
(#33971680)
> German famously has a word for nearly everything. I'm not sure that's elegant, in that it requires learning a far greater number of words.
That's not quite how it works though, right? Compound words are exactly that, combining two or more words to narrow down the meaning, without having to invent a new word. It's almost like "if not" vs "unless"...
Re:Read this post ‘unless’ you’re not a Ruby developer
by KMag on Tuesday December 13, 2022 @12:50PM
(#33972721)
Correct. The chief difference between English and German in this respect is the use of spaces (and what is considered a word). In German, you can basically drop the spaces from a noun phrase and call it a word, but it's basically a low-consequence surface syntax difference.
Side note: ancient Greek didn't use spaces, and many other languages (Thai and Written Chinese are the ones with which I'm most familiar) either don't use spaces or make spaces optional. The distinction between a phrase and a word gets a bit blurry at times, and I find the distinction is seldom useful, particularly when making comparisons across languages.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @05:33PM
(#33977097)
Fascinating! I had no idea. I stand by my main point, but perhaps German wasn't a good example. It's just the one that comes up all the time when people say "Did you know X language has a word for Y?", it's almost always German. Now I know why!
Re:Read this post ‘unless’ you’re not a Ruby developer
by jewel on Tuesday December 13, 2022 @10:12AM
(#33969862)
It's Ruby though, where Array has "size", "length", and "count", all of which are equivalent. The programmer chooses which one they prefer based on the context or their style or the phase of the moon.
Ruby inherits the Perl philosophy of "There's more than one way to do it". Compare with Python, and its "There should be one — and preferably only one — obvious way to do it."
It's true that it makes the compiler less elegant, but Ruby optimizes for the programmer at the expense of the compiler.
Re:Read this post ‘unless’ you’re not a Ruby developer
by vidarh on Tuesday December 13, 2022 @02:54PM
(#33974759)
It can also take an argument and will then return the count of the number of items which compares equal to the argument.
"count" is only equivalent to "length" and "size" when called with no argument and no block, and should be slower for that case (it includes a comparison of arity and a call to rb_block_given_p() in MRI before it returns the array length).
Re:Read this post ‘unless’ you’re not a Ruby developer
by shakow on Tuesday December 13, 2022 @10:13AM
(#33969889)
A for can be replaced by a while and a jump, that does not make it more or less elegant.
IMHO, something ‶elegant″ in programming is not something that can't be built form something else (or we will all end up in writing only CMOVs), but something that conveys the meaning of its author precisely and concisely – which makes it inherently subjective. I'm in the `unless` team, I can perfectly understand if you are in the `no unless` team, but this argument does not make a lot of sense.
Re:Read this post ‘unless’ you’re not a Ruby developer
by JasonFruit on Tuesday December 13, 2022 @12:05PM
(#33971766)
Note that I said 'trivially'. The structure and meaning of an 'unless' construction is the same as 'if', adding or removing only a negation. Using 'while' and a jump to construct a loop is much more expressively distant from 'for'.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nine_k on Tuesday December 13, 2022 @10:58AM
(#33970580)
The `for` is a very ergonomic syntax to mapping a computation to every element of a sequence. The `while` does a really different thing, it's not about sequences at all, but about checking some bit of mutable state repeatedly.
Re:Read this post ‘unless’ you’re not a Ruby developer
by shakow on Tuesday December 13, 2022 @11:06AM
(#33970714)
> The `for` is a very ergonomic syntax to mapping a computation to every element of a sequence.
The very ergonomic solution to map a computation to every element of a sequence is `map`. In this case, `for` is filled with bookkeeping that does not matter.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nine_k on Tuesday December 13, 2022 @02:30PM
(#33974420)
I edited out "syntax sugar" that was in the post initially.
Also, the `for` operator definitely predates the `map` function. Some people also prefer `map` to be more or less pure and expect it to return a usable list; `for ` has no such expectation, it e.g. may consist solely in printing elements.
Re:Read this post ‘unless’ you’re not a Ruby developer
by aaronbrethorst on Tuesday December 13, 2022 @12:07PM
(#33971799)
One of the hallmarks of Ruby is a full embrace of the notion of There's More Than One Way To Do It. Generations of developers around the world have seen this as being a core part of Ruby's elegance—at least to their minds (myself included).
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:18AM
(#33969956)
I'm getting the impression that this is not universally true. It's true for me. I find the word "unless" helpful when it eliminates double negatives.
But there are enough people on this thread who feel differently that it makes me wonder if maybe we're wrong. If code is meant to be read and understood by all, and if "unless" is confusing to a large number of people, maybe those of us who like it should knock it off.
I do find it more elegant and easier to read, but maybe you and I can process double negatives easier than the anti-unless crowd are able to process "unless" logic.
If that's the case, I'd be willing to sacrifice my preference for "unless" for the greater good.
Re:Read this post ‘unless’ you’re not a Ruby developer
by lsaferite on Tuesday December 13, 2022 @10:51AM
(#33970463)
> double negatives
Could you give an example of a double negative in this case?
I ask because using "if" does not lend itself to double negatives in my experience, but just thinking about "unless" I see double negatives being an issue (since unless is already negating the operand).
Re:Read this post ‘unless’ you’re not a Ruby developer
by chillfox on Tuesday December 13, 2022 @03:56PM
(#33975653)
People are different, so different things click with how they think.
I would likely not be a programmer if it weren’t for Ruby and it doing things different.
I had tried to learn programming for years (JavaScript, Python, Java, C#), none of it stuck or progressed beyond following tutorials and one of the things I had serious issues with was negation.
Then I came across Ruby and it just kinda clicked into place like no other language had. With Ruby I was able to do my own things within a month.
Now I don’t really have a problem picking up other languages anymore. But there’s others out there right now struggling to learn programming and there should be as many programming languages doing things different as possible to increase the chance that they come across one that is obvious for the way they think.
This idea of there should only be one way of doing things is poison in my opinion.
Re:Read this post ‘unless’ you’re not a Ruby developer
by asdajksah2123 on Tuesday December 13, 2022 @10:27AM
(#33970080)
Unless has negation built in.
Which is why unless is such a hard concept for people to grasp, not just in code, but also in regular English.
At least the "if not" makes the negation explicit, which can then be easily eliminated using several different techniques (early return, swap with the else condition) if the negation is confusing enough.
However, "unless" necessarily includes negation because that's how the word is defined.
Re:Read this post ‘unless’ you’re not a Ruby developer
by mattarm on Tuesday December 13, 2022 @12:04PM
(#33971761)
> Which is why unless is such a hard concept for people to grasp, not just in code, but also in regular English.
This is the first I've heard about this confusion over the word "unless" in English.
In spoken English I do notice that most often the "unless" comes after a statement. Example: "I'll be there on time, unless the bus is late." That is more clear (to me) than "I'll be there on time, if the bus is not late." Maybe not by coincidence, I tend to like "unless" when it follows the action in in Ruby code, too.
Re:Read this post ‘unless’ you’re not a Ruby developer
by taeric on Tuesday December 13, 2022 @10:22AM
(#33970019)
In lisp, "unless" is a great way to signal that there will not be a dual branch. Similarly, they have "when" for the positive case only. They also have the advantage of not needing a "progn" segment if you want to do more than 1 thing on the case that they are "true".
I confess at first I thought they were somewhat superfluous, but they are more readable now that I'm used to them. Completely agreed on it being stylistic, mainly.
Re:Read this post ‘unless’ you’re not a Ruby developer
by enw on Tuesday December 13, 2022 @12:04PM
(#33971759)
For me honestly it's one of the (many) things I dislike the most about Ruby.
Sure, I understand the "elegant" aspect, two symbols are shortened to one (although I'd argue that's not that important when it comes to clarity and legibility).
But every time I read "unless" in code it's quite jarring. I have to consciously translate it to "if not", and even then seeing the "unless" keeps tripping me off, perhaps because it's awkward in English to start a sentence out of the blue with "unless".
Re:Read this post ‘unless’ you’re not a Ruby developer
by ravenstine on Tuesday December 13, 2022 @12:26PM
(#33972234)
It's a matter of taste, but I tend to agree that the more features or constructs a language has, no matter how terse or convenient, the more unnecessary complexity is generated by using that language.
The `unless` keyword makes the interpreter slightly more complicated and is another piece of language the human brain needs to recognize. It may seem inconsequential, but grains of sand make a hill, as they say.
My ideal language would leave out pretty much anything that can be achieved with more basic constructs. It would of course have if-else, and leave out `unless`, but there would also be no switch statements or ternaries. Branching must be done with if-else or by looking up a value in a hash. No `for` or `while` loops because a simple `loop` construct with `continue` and `break` statements can do everything that `for` and `while` could do in other languages. No classes or inheritance because they're magical and they can be effectively simulated by the end developer if that's what they really want.
What I think would be really cool is to have a language with a syntax like Ruby but with only the most basic of programming language constructs.
Re:Read this post ‘unless’ you’re not a Ruby developer
by ravenstine on Tuesday December 13, 2022 @01:52PM
(#33973854)
I've thought about that, but that's closer to the metal than I prefer and I think it's not beneficial for less experienced programmers.
Structured programming is, I believe, a good idea for the vast majority of use cases. Though one can technically use structured programming while using goto, encouraging goto can therefore allow programmers to go down a path that is counterproductive. It's basically the opposite end of the spectrum from OOP where encouragement of rampant objectiveness and inheritance makes programmers write code that is way too complicated.
There's absolutely a place for goto. I once made a "language" (actually YAML) specifically for developing for the Amazon Alexa platform, and it used something similar to goto called "go to scene" and "go to random". For that sort of thing, goto can be much more practical and even easier to reason about than "better" constructs in general purpose high-level programming languages. It's just not something I would consider appropriate for the kind of language I am proposing, though I still ponder on it.
Re:Read this post ‘unless’ you’re not a Ruby developer
by KMag on Tuesday December 13, 2022 @01:13PM
(#33973173)
Many language implementations internally translate source into a simplified de-sugared dialect as you describe as an early compilation step. I believe both ghc and rustc currently do this.
Though, I think it's rare to expand a pattern match/switch into an if-else tree, and much more common to expand an if-else into a 2-way pattern match/switch.
If you're really keen on such a language, you could fairly easily implement such a language as a pre-commit hook source code re-formatter so that all of the source in your repository is in your favorite language subset.
Re:Read this post ‘unless’ you’re not a Ruby developer
by adverbly on Wednesday December 14, 2022 @11:16AM
(#33985643)
> Which of the following is better?
if !ruby_dev
or
unless ruby_dev
As a ruby dev of 5+ years, I still have an easier time with `if !ruby_dev`. I have to translate `unless` to `if !` every single time to grok something. Almost like an extra step in an algebraic expression being simplified.
Re:Read this post ‘unless’ you’re not a Ruby developer
by dyingkneepad on Tuesday December 13, 2022 @03:41PM
(#33975421)
I have problems with 'unless' even in plain English text. I'm pretty good at English, I live in the USA, but I was not born here and my native language does not have a word for 'unless' (you have to use 3 words to express that idea!). I love Ruby, but the 'if' variation always get immediately parsed by my brain, while the 'unless' variation requires many seconds of thinking.
Re:Read this post ‘unless’ you’re not a Ruby developer
by systems_glitch on Tuesday December 13, 2022 @10:03AM
(#33969724)
Came here to say this. If you don't like it, don't use it, but it sure does seem to make things easier for other developers (Ruby and not-Ruby-but-assigned-to-this project) to understand. I like it.
Re:Read this post ‘unless’ you’re not a Ruby developer
by welder on Tuesday December 13, 2022 @09:43AM
(#33969473)
I treat the 'if' statement and the '!ruby_dev' conditional as separate entities. That allows thinking of the conditional alone in boolean logic terms, instead of having to consider the outside prefix statement too.
Therefore, coming from a computer science background I don't like 'unless'.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:10AM
(#33969839)
I could see that. Maybe it really is because I'm more of a writer than a computer scientist.
(For context: I dropped out of comp sci and took a job as a web dev ~18 years ago. Never looked back. But have ended up learning more about copywriting and marketing than computer science along the way.)
Re:Read this post ‘unless’ you’re not a Ruby developer
by philote on Tuesday December 13, 2022 @11:32AM
(#33971136)
I'm a computer scientist and not much of a writer yet I prefer the use of "unless" over a negated "if". Then again, at the start of my career I used quite a bit of Perl and it was created by a linguist.
Re:Read this post ‘unless’ you’re not a Ruby developer
by chrisandchris on Tuesday December 13, 2022 @10:29AM
(#33970111)
Doing Rails for half a year now and usually are pretty good at mental models.
I always have to stop at an unless because the double-negative is really hard to evaluate in the mind IMHO.
IMHO unless leads to unnecessary nesting. In your example, it reads like _most_ people are ruby dev. I try to keep the most-often excecuted flow as flat as possible (happy path) and just try to nest for additional/special cases. Unless just tries to do... different.
Re:Read this post ‘unless’ you’re not a Ruby developer
by j33zusjuice on Tuesday December 13, 2022 @05:48PM
(#33977320)
“If you are [not]” serves a different function than “unless.”
“Unless” is a conjunction, and its presence creates a double negative with the end of the sentence making the sentence extra clunky (“unless you’re a Ruby dev, you shouldn’t read this article.”)
A few iterations later, we get to the correct syntax, “read this article if you’re a Ruby dev.”
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:19AM
(#33969972)
Fascinating! I find it slightly easier to understand "unless" than "if not". But only oh-so slightly, and probably not enough to justify making it harder for others to read my code.
Re:Read this post ‘unless’ you’re not a Ruby developer
by topaz0 on Tuesday December 13, 2022 @12:02PM
(#33971709)
I agree with you. I think the complaints come down to "don't give people more confusing ways to write conditionals". And I agree with the complainers that it is easy to write conditionals in a confusing way, and that there are simply more confusing ways to write them when you can also use unless. But I think the problems come from not taking the time to make the conditional easy to parse, which is an issue whether or not you have unless. And it's not just trading if ! for unless (or if for unless !) -- sometimes it's "if valid" vs "unless !valid" vs "if !invalid" vs "unless invalid", depending whether it was easier to write the predicate for valid or for invalid. Even working in a language without unless, I frequently find myself encountering these difficulties, and I find that the only thing that helps is treating it like writing and deciding what logical progression will be the most helpful for the reader. What's most helpful for the reader won't always be to use unless, but sometimes it will, so it's nice to have the option.
Re:Read this post ‘unless’ you’re not a Ruby developer
by kuratkull on Tuesday December 13, 2022 @12:48PM
(#33972674)
'if !<something>' clicks instantly.
for 'unless' I have to read out the statement in my head, and draw mental logic lines about what condition this is checking.
Re:Read this post ‘unless’ you’re not a Ruby developer
by peruvian on Tuesday December 13, 2022 @10:46AM
(#33970364)
Different taste I guess. I work in Python and always go out of my way to write "if thing is True" or "if thing is False" nowadays to make conditions clear and uniform.
Re:Read this post ‘unless’ you’re not a Ruby developer
by geuis on Tuesday December 13, 2022 @02:51PM
(#33974726)
Nope. It's needless confusion. We're programmers who have stuff to do, and syntactic stuff like unless are not helpful.
if (true) and if not(true) is simple and elegant, and doesn't require any person on my team to stop their flow to puzzle out what the code is supposed to be doing at that point.
Re:Read this post ‘unless’ you’re not a Ruby developer
by class4behavior on Tuesday December 13, 2022 @03:44PM
(#33975479)
But inventing totally new languages even for billion dollar projects is totally fine?
You want a well-justified, inclusive, and consistent yet adaptable style when collaborating with people. It would be selfish to gatekeep a policy without regard for those principles.
Re:Read this post ‘unless’ you’re not a Ruby developer
by nickelcitymario on Tuesday December 13, 2022 @10:08AM
(#33969815)
I agree entirely that it can be misused. I'm not sure how often it's misused versus used properly. But I don't see why I should give up a useful logic tool just because others don't know how to use it well?
Let me put it this way: Are there _any_ programming paradigms that don't get poorly used? We need to learn how to use our tools well, not reduce them to banality.
Re:Read this post ‘unless’ you’re not a Ruby developer
by burke on Wednesday December 14, 2022 @10:25AM
(#33984720)
No, I just think for all ruby is bought into these guard clauses, it's sad that we generally reject the feature that allows putting either the condition or the consequence first, depending on which reads better.
Re:Read this post ‘unless’ you’re not a Ruby developer
by micromacrofoot on Tuesday December 13, 2022 @10:55AM
(#33970540)
I used to work at a garage, and while an impact wrench can be the fastest way to put a tire back on a car, I eventually banned it entirely.
Everyone's lazy or overwhelmed at some point, and it made mistakes too easy to make (the problem is that it overtightens the lug nuts because the ease of use removes the proper physical feedback).
In situations where you don't have the bandwidth to perfectly educate everyone and enforce rules, sometimes it's easier to limit the toolset. A tire iron can be misused too, but it's a little harder.
Re:Read this post ‘unless’ you’re not a Ruby developer
by PaulRobinson on Tuesday December 13, 2022 @10:24AM
(#33970036)
As the article starts to explore, it's more useful in the context of a single line conditional with a single boolean to evaluate, or what I sometimes call a "dangling conditional". This is valid ruby:
do_something if boolean_expression
All unless does is allow you to negate it using an expression that's more natural to most people
do_something unless boolean_expression
To me the negation of an if with ! is less clear in this context. For example:
puts "That's a prime" if is_prime?(variable)
makes sense. So does:
puts "That's not a prime!" unless is_prime?(variable)
Far more so than:
puts "That's not a prime!" if !is_prime?(variable)
The author decides however to add more conditionals. Fine, don't do that. Or that it's unreadable in some contexts. Fine, don't do that either.
The whole point of Ruby - the only reason it really exists - is that it should be fun and easy and not require you to spend too much time stressing over rules. If you read a piece of Ruby and don't like it, change it. It's not Python - there is more than one way. Use the way that makes sense in the context you're using it.
If you can't trust yourself or your team to do that wisely in a project, consider changing languages, because guess what? The language isn't going to change because you don't like that thing.
Re:Read this post ‘unless’ you’re not a Ruby developer
by neilv on Tuesday December 13, 2022 @10:50AM
(#33970444)
Maybe these dangling conditionals are easier for you to read, but not for me.
Were I reading through real-world code that did things like that:
"OK, then we do this, and then we do that, and then-- Oh wait! Backtrack! We didn't do that thing at all! ... Now where were we, on our actual bug, before some very special person's syntactic speed bumps?"
Re:Read this post ‘unless’ you’re not a Ruby developer
by Draiken on Tuesday December 13, 2022 @11:30AM
(#33971105)
But these are not absolutes. You can learn to use and read `unless` just as effortlessly as you did with `if`. I didn't learn to use/read `unless` on college. But I did focus on trying to learn these things and today I have another tool in my belt.
It's an opportunity to get better at something versus banning it from usage because we aren't used to it.
Growing is, for me, almost always the right choice.
Re:Read this post ‘unless’ you’re not a Ruby developer
by neilv on Tuesday December 13, 2022 @12:01PM
(#33971689)
Dangling conditionals the parent was talking about. Where the conditional comes after the thing you told it to do. Computationally, that's increased backtrack/lookahead for no good reason.
Regarding `unless`, that's a different matter. I was actually the person who proposed adding an `unless` syntax to Racket, and later regretted it. I was bikeshedding, before I knew something more useful to do.
This isn't about learning new things to add to our mental toolbox. This is about our difficulty to introspect on our own thought processes and effectiveness, and about bikeshedding.
Software engineering competence is hard, or we wouldn't have all the huge expenditures, slipped project schedules, and rampant security vulnerabilities. Redundant syntax forms that objectively makes it harder to read (see the lookahead and parser theory), solely because someone imagined it was sometimes easier to read this way (see dying languages Perl and Ruby) is just wasting our time, when we could be tackling the real problems.
(Though us pulling theories about programming and process out of our posteriors, to defend to the death, is arguably half our problem in industry right now.)
Re:Read this post ‘unless’ you’re not a Ruby developer
by torton on Tuesday December 13, 2022 @10:35AM
(#33970194)
The impetus to write the article seems to be Rubocop, whose rules are suggesting a specific way of doing things. But specific instances of a specific rule can be overridden, and if a rule proves itself to be more trouble than it's worth it can be disabled entirely.
I would go so far as to suggest jumping into Rubocop "cold turkey", meaning all rules on, is not very helpful on an existing codebase. The way my team approached Rubocop on a particular large legacy codebase was to start with a few hand picked rules that were non-controversially good, and discuss new rules one at a time as we gradually fixed the existing issues.
Re:Read this post ‘unless’ you’re not a Ruby developer
by ufmace on Tuesday December 13, 2022 @12:26PM
(#33972249)
I agree with this - I always found the single ! in conditionals to be too easy for your eyes to slide past and miss. Using `unless` makes it jump out harder that you're only doing the thing if the condition is `false`.
Re:Read this post ‘unless’ you’re not a Ruby developer
by shortcake27 on Tuesday December 13, 2022 @06:10AM
(#33967268)
I really don’t understand the author’s point about adding extra conditions. They admit that many people will find a single condition with `unless` more readable. They then complain that it becomes unreadable when adding another condition. OK, so swap it out for an `if` at that point. No one is forcing you to keep using `unless` if the requirements change. “You should use a suboptimal solution to cater for unknown future requirements” is a terrible argument.
Re:Read this post ‘unless’ you’re not a Ruby developer
by roboben on Tuesday December 13, 2022 @06:32AM
(#33967468)
That’s exactly how I use ‘unless’. Simple on condition (no else branch) use cases in one liners, anything more complex, I move to if. Best of both world I’d say!
Re:Read this post ‘unless’ you’re not a Ruby developer
by aqme28 on Tuesday December 13, 2022 @07:03AM
(#33967758)
That’s the generally recommended style! I hate this post. It’s arguing against something that is well known to be a bad practice (that’s fine), but it seems to put the fault for this on Ruby itself.
Re:Read this post ‘unless’ you’re not a Ruby developer
by doodpants on Tuesday December 13, 2022 @09:45AM
(#33969500)
Indeed. I personally never fail to avoid not using "unless", unless there isn't a lack of extra conditions such that not refraining from instead using "if" wouldn't avoid not being less clear.
Re:Read this post ‘unless’ you’re not a Ruby developer
by asdajksah2123 on Tuesday December 13, 2022 @10:32AM
(#33970157)
The author's point is that conditions in code tend to add up.
What may start as a simple single condition, may not remain that way a year later.
Since there's always the possibility of a certain conditional becoming more complicated, it makes sense to opt for the equivalent solution that makes adding those additional conditions easier.
The alternative is to change the keyword when you add those additional conditions, but in most workplaces it's very possible that someone with less rigor than you might come in and add those new conditions and not make the change.
And then if you want to add a new condition you need to parse and understand the more complicated new conditional first, before you can change it.
This adds a lot of maintainability risk for what appears to be, in the best case, a very minor benefit.
Re:Read this post ‘unless’ you’re not a Ruby developer
by WillPostForFood on Tuesday December 13, 2022 @10:49AM
(#33970419)
That strikes me as a premature optimization. If you have a single condition, and unless makes it more readable, use unless. If the conditions do pile up in the future, change it to an if.
Re:Read this post ‘unless’ you’re not a Ruby developer
by quest88 on Tuesday December 13, 2022 @11:45AM
(#33971398)
Great, now you've got this weird logic on your style guide that your code reviewers will have to point to, and hopefully the new engineers on your team will remember. But maybe they're in a hurry and will quickly add another expression just this one time, multiplied by many engineers.
Re:Read this post ‘unless’ you’re not a Ruby developer
by shortcake27 on Tuesday December 13, 2022 @04:46PM
(#33976371)
While I agree with the other comment re premature optimization, when using guard clauses you can also break up your conditions into multiple statements which is arguably the most readable solution. The author’s example could be written as:
return unless valid_token
return if expired?
This scales extremely well if you’re concerned about future conditions.
Re:Read this post ‘unless’ you’re not a Ruby developer
by Draiken on Tuesday December 13, 2022 @07:37AM
(#33968082)
I believe this is somewhat prevalent in the Ruby community as of late where people try as hard as possible to "lock down" the language and limit the ways you can get to a solution in the name of the proverbial "ease of understanding".
I wholeheartedly disagree and believe we should instead grow the developers to understand these different approaches as opposed to labeling half of the language "bad practice".
As I said in another comment. Ruby was built to have multiple ways of doing the same tasks and criticizing it for this is... pointless.
Yes people can create monstrosities with all of these variations, but that's true with any powerful tool. If you dislike Ruby for being Ruby, pick another language.
Re:Read this post ‘unless’ you’re not a Ruby developer
by techdragon on Tuesday December 13, 2022 @08:01AM
(#33968278)
I love an expressive programming language, it’s why Go makes me feel like I’m brushing my teeth with sandpaper…
But there’s such a thing as too much flexibility, expressiveness and flexibility often go hand in hand as flexible language lets you make things as expressive as you want… but things can be expressive without the same level of flexibility if they are well designed.
I find Rust strikes a good balance for low level language work, it feels more expressive than C because of higher level language features but it’s not necessarily as flexible as C with things like the borrow checker nagging you to be safe unless you turn it off.
Lisp… too flexible, too expressive. Lisp code reminds me of the phrase “that depends on what the definition of is, is”.
Scheme and scheme likes including weird step cousins like JavaScript share the unfortunate result of this and your drowning in custom DSLs and no one quite codes the same way unless you have rigorous tooling to enforce a team style.
Ruby falls foul of this for me too. It’s too flexible, it’s very expressive and I enjoyed reading the tutorials and learning the basics. But the moment I discovered real code I was immediately recoiling in horror …. It was a disaster… a spaghetti mess of overrides redefining and meta-programming in general. It made it impossible for me to ever trust the environment I coded it since I had to constantly inspect everything to make sure someone hadn’t done something crazy like enhanced the “+” sign to transform numbers to strings for avoiding something like a sql injection risk in a specific context and whoopsie, leaked the behaviour globally so now any time you added integers you got concatenated strings… but only after the library was dynamically loaded on first query … maddening stuff…
Re:Read this post ‘unless’ you’re not a Ruby developer
by FpUser on Tuesday December 13, 2022 @09:50AM
(#33969567)
I do not program in Ruby as there was no business need but I have rough idea on what it can do. My view on the horror you've encountered is that the so called "programmers" that produce such abominations should be sent back to school.
I understand business idea of having monkeys producing code for cheap but I think this approach is misguided.
Re:Read this post ‘unless’ you’re not a Ruby developer
by FpUser on Tuesday December 13, 2022 @09:44AM
(#33969480)
>"As I said in another comment. Ruby was built to have multiple ways of doing the same tasks and criticizing it for this is... pointless. Yes people can create monstrosities with all of these variations, but that's true with any powerful tool. If you dislike Ruby for being Ruby, pick another language."
Exactly the reasons I use C++. Well, after crazy performance, efficiency and single executable deployment.
Re:Read this post ‘unless’ you’re not a Ruby developer
by rubyist5eva on Tuesday December 13, 2022 @09:44AM
(#33969479)
> we should instead grow the developers to understand these different approaches as opposed to labeling half of the language "bad practice".
> As I said in another comment. Ruby was built to have multiple ways of doing the same tasks and criticizing it for this is... pointless.
Agreed 100% with this take. If I only wanted 1 way to accomplish something no matter how inelegant it might be in that context, I would use Python. I choose Ruby specifically because of how expressive it is. It makes it a bit tougher when working in a team with 2 or more opinionated devs, ie. "should we use more functional or more OO approaches to solve a problem" but this is a culture and communication issue, not a language problem. Having a good rubocop setup and staying within the confines of your agreed upon ruleset is a good start.
For example you can use rubocop to enforce dissallowing `unless !condition`, then it's just not an issue anymore - these kinds of issues dissapear before code even makes it to review.
Re:Read this post ‘unless’ you’re not a Ruby developer
by saghm on Tuesday December 13, 2022 @01:57PM
(#33973939)
> “You should use a suboptimal solution to cater for unknown future requirements” is a terrible argument
Not exactly the same, but over the years I've heard people argue against having super customized shell configurations (e.g. completions, prompts, highlighting) because they won't be available if you have to use a different environment (e.g. sshing into a temporary cloud server to debug something failing in CI). I don't pretend that other people will value tradeoffs the same as me, but it's a mindset I can't really imagine ever having. I'd rather be happy most of the time even if I know I'm going to be unhappy for short periods occasionally in the future, and I don't really think the slight efficiency gain in the uncommon case due to being used to not having nice features is going to outweigh the larger efficiency gain for the much more common case.
At the risk of straying entirely off-topic, I've seen this in non-professional contexts at times as well; I recently had a friend in an online game mention that he doesn't like to utilize a convenience feature that happens for a couple weeks each year as part of a special even because he would miss it too much the rest of the time. While I don't think the tradeoff is quite as obvious to me for this sort of thing, I feel like occasionally having a fun temporary addition is worth it just for the change of pace, and I'm generally able to adapt to the loss of a minor convenience relatively quickly after losing it. It seems sort of like a question of "maximizing peak happiness" versus "minimizing peak unhappiness" or even "maximizing average happiness"; I like having something to get excited about every now and then even if it leads to feeling blase about things for a bit later because I get bored if things stay the same for too long.
Re:Read this post ‘unless’ you’re not a Ruby developer
by meatmanek on Tuesday December 13, 2022 @05:10PM
(#33976742)
As an analogy to your shell customization thing:
I switched from QWERTY to Dvorak a long time ago, a few years after learning to touch type. Does it make me more efficient on my own computer? Probably slightly -- Dvorak really is a well-designed keyboard layout, but it's impossible to know whether my WPM is any higher than it would've been on QWERTY. However, I make way more mistakes and type way more slowly whenever I sit down at a QWERTY keyboard. I had to re-learn how to touchtype QWERTY after switching to Dvorak, and my skill never got back to the same level. It also leads to extra inconvenience every time I lend my computer to someone else, install a new OS, etc.
I think this means my average typing speed (weighted average of the time spent at Dvorak keyboards + QWERTY keyboards) is probably flat or possibly lower than if I had just stuck with QWERTY. When combined with all the effort I spent learning Dvorak, re-learning QWERTY, and making many mistakes in the early years, I think my lifetime productivity is probably even lower. I don't recommend that people switch, even if I think Dvorak really is a better layout.
Re:Read this post ‘unless’ you’re not a Ruby developer
by stefano_c on Tuesday December 13, 2022 @06:04AM
(#33967211)
I've been writing Ruby for 20+ years and "unless" (the whole language, actually) immediately clicked for me when I first learned it.
That said, I only use it in 2 cases:
* as a trailing condition (do_something unless this), mainly for early returns
* as the only arm of a multi-line block (unless this ... end, no "else" blocks - Rubocop would yell at me anyway)
And then only if the condition is either a simple value, or a combination of simple values (this && that, this || that).
That's it. Never had a problem with double negatives or accidentally inverting the logic.
Re:Read this post ‘unless’ you’re not a Ruby developer
by pmontra on Tuesday December 13, 2022 @06:50AM
(#33967624)
This is basically how I use unless too. Complex conditions are complicated enough to grasp without inflicting an unless on me. But for simple cases it is a nice to have feature.
Of course one can avoid it at all but of course one cannot avoid to spend time on it when reading somebody's else code.
Re:Read this post ‘unless’ you’re not a Ruby developer
by masklinn on Tuesday December 13, 2022 @06:50AM
(#33967629)
FWIW HN does not support markdown lists (or markdown anything other than emphasis and code blocks really), you need to add an empty line between your “list items” so the comment parser treats them as separate paragraphs instead of munging them together as just one.
Re:Read this post ‘unless’ you’re not a Ruby developer
by moonchrome on Tuesday December 13, 2022 @04:34AM
(#33966545)
I don't have a problem with double negation but I hate ruby for this kind of design - pointless aliases for everything.
It's the exact opposite of pythons "There should be one– and preferably only one –obvious way to do it" - they intentionally create solutions that have zero practical benefit - it's just fuels arguments based on preferences and introduces mental overhead due to inconsistency.
Re:Read this post ‘unless’ you’re not a Ruby developer
by sshine on Tuesday December 13, 2022 @04:42AM
(#33966600)
To be fair, Ruby inherited "unless" from Perl.
And Perl literally has the opposite design principle, TIMTOWTDI or "there is more than one way to do it".
I'm not arguing here -- I prefer the "one obvious way" principle.
But you can design a beautiful programming language without regard for the long-term learnings of software engineering.
I always liked Perl's "unless", and I always made sure to not abuse it with double negatives or other contorted conditions that are, in themselves, reasonable. I also promised myself I wouldn't write very big programs in Perl.
Re:Read this post ‘unless’ you’re not a Ruby developer
by TurboHaskal on Tuesday December 13, 2022 @05:04AM
(#33966746)
I came to Ruby from Perl, and I love `unless`. One of the first things I do in any Lisp is build my own unless macro unless the dialect already has it :)
Re:Read this post ‘unless’ you’re not a Ruby developer
by gpvos on Tuesday December 13, 2022 @01:34PM
(#33973579)
Okay. Now compare:
die "You may only use port numbers 1024 and higher"
unless $port >= 1024 || is_root(current_uid());
die "Port numbers 1024 are forbidden"
if $port < 1024 && !is_root(current_uid());
Re:Read this post ‘unless’ you’re not a Ruby developer
by lloeki on Tuesday December 13, 2022 @04:59AM
(#33966714)
> Everyone has an individual background. Someone may come from Python, someone else may come from Perl, and they may be surprised by different aspects of the language. Then they come up to me and say, 'I was surprised by this feature of the language, so Ruby violates the principle of least surprise.' Wait. Wait. The principle of least surprise is not for you only. The principle of least surprise means principle of least my surprise. And it means the principle of least surprise after you learn Ruby very well. For example, I was a C++ programmer before I started designing Ruby. I programmed in C++ exclusively for two or three years. And after two years of C++ programming, it still surprises me.
Re:Read this post ‘unless’ you’re not a Ruby developer
by vidarh on Tuesday December 13, 2022 @06:04AM
(#33967209)
And I love it for exactly this kind of design. It's what makes well-written Ruby read well. And while it's one more way of making badly-written Ruby read badly, in my opinion at least with Ruby you have the option of writing code that reads well. I've yet to see Python code that looks readable to me.
Re:Read this post ‘unless’ you’re not a Ruby developer
by chillfox on Tuesday December 13, 2022 @10:29AM
(#33970113)
The problem is that what is obvious depends upon your way of thinking. To me very little in Python makes sense, but I understand that it does to someone and that’s cool. There’s no reason to hate on a language just because it doesn’t click with your way of thinking.
Re:Read this post ‘unless’ you’re not a Ruby developer
by aqme28 on Tuesday December 13, 2022 @07:21AM
(#33967928)
I love Ruby for this kind of stuff. You don't have to have arguments about which syntax you prefer, you can just use the one you prefer and let your coworkers use theirs.
However, a lot of developers love very strict style guidelines. I've never understood why, but it's a discussion I get into very very often.
Re:Read this post ‘unless’ you’re not a Ruby developer
by soiler on Tuesday December 13, 2022 @12:38PM
(#33972477)
Hm, I have the exact opposite interpretation. This is exactly the kind of feature that leads to arguments. If `unless` didn't exist, what argument could people be having about using `if !`?
In a shared codebase, I think there should be as few (equally effective) ways to express an idea as possible. (Obviously there can be more- and less-efficient ways to write a function; I'm referring only to style.) The more arbitrary choices people have, the more time is wasted on choosing one.
If you're coding alone, that's fine - you just pick what you like, and spend as long as you like making that decision. But in a shared codebase, developers writing in different styles is a net negative on quality & readability. Spending time debating which style to prefer is a worthwhile, but unnecessary time sink. Automatically enforcing a pre-defined style is efficient and effective - that's why Prettier exists, is widely used, and has few configuration options.
Re:Read this post ‘unless’ you’re not a Ruby developer
by aqme28 on Tuesday December 13, 2022 @07:10PM
(#33978198)
> In a shared codebase, I think there should be as few (equally effective) ways to express an idea as possible...The more arbitrary choices people have, the more time is wasted on choosing one.
I highly disagree! In my experience, forcing arbitrary style leads to so much more time wasted as people debate exactly which styles to enforce.
> But in a shared codebase, developers writing in different styles is a net negative on quality & readability. Spending time debating which style to prefer is a worthwhile, but unnecessary time sink
I disagree with this too. I have never found this type of style to be something that actually impacts readability and quality. If you using `if !` and I using `unless` is the problem with the codebase, that's not so bad.
I have to say, this is why I'm a huge fan of Python's black. It lets me write however I want, while you get to read my code in a consistent style.
Re:Read this post ‘unless’ you’re not a Ruby developer
by soiler on Wednesday December 14, 2022 @01:21PM
(#33987502)
Fair enough, I understand every team is different.
> forcing arbitrary style leads to so much more time wasted as people debate exactly which styles to enforce
If this is happening often, I would unambiguously call that a problem, though. It should only happen once (and then, when enough has changed in the frameworks, maybe once again). This is exactly the philosophy Prettier takes: it is purposely difficult to change. It works really well as it is, and keeping it constantly optimized for community preference would be an anti-pattern.
> I disagree with this too. I have never found this type of style to be something that actually impacts readability and quality. If you using `if !` and I using `unless` is the problem with the codebase, that's not so bad.
I more or less actually agree with you on this. Small stylistic differences are generally negligible. But variations add up, and some are more egregious than others. I consider this more of a guiding philosophy than a rule; `if!` vs `unless` on its own is not a real problem.
Re:Read this post ‘unless’ you’re not a Ruby developer
by Draiken on Tuesday December 13, 2022 @07:28AM
(#33967994)
People can prefer the "one obvious way" and you can use a language that has that as its motto. Ruby was built with "developer happiness" as an objective and I don't see it changing any time soon.
I'll never understand these sorts of articles because they criticize the subject for not being what they explicitly aren't.
"I hate spoons because they can't cut like knives"
Re:Read this post ‘unless’ you’re not a Ruby developer
by drstewart on Tuesday December 13, 2022 @06:26AM
(#33967402)
Wow, I didn't realize Python did this. So, for example, does it enforce functions with single returns or ones with multiple return sites? Also, does it prefer shallowly nested functions with guard clauses or highly nested if / else clauses?
Really curious to see the one and only one obvious way these are handled.
Re:Read this post ‘unless’ you’re not a Ruby developer
by soheil on Tuesday December 13, 2022 @05:11AM
(#33966782)
It's not pointless, it makes code read better. It's another option to have. It's not meant for every use case. It indicates you don't understand Ruby if you find yourself using an "unless" in a complex boolean operation. It's meant for simple cases like an inline return statement
Re:Read this post ‘unless’ you’re not a Ruby developer
by ilyt on Tuesday December 13, 2022 @09:05AM
(#33968999)
return if !User.exists(id=100)
reads just fine and takes less letters. I don't think unless is "bad", it's just unnecessary
> It indicates you don't understand Ruby if you find yourself using an "unless" in a complex boolean operation. It's meant for simple cases like an inline return statement
unless `git status -s | grep -v 'RAILS_VERSION\\|CHANGELOG\\|Gemfile.lock\\|package.json\\|version.rb\\|tasks/release.rb'`.strip.empty?
abort "[ABORTING] `git status` reports a dirty tree. Make sure all changes are committed"
end
is not exactly very readable and this
unless connection.adapter_name == "Mysql2" && options[:id] == :bigint
if [:integer, :bigint].include?(options[:id]) && !options.key?(:default)
options[:default] = nil
end
end
isn't glancable either. Just random snippets from Rails code. You can see how author wanted some bonus points and used unless, if, and ! too. Sure it isn't hard to figure out but it makes it needlesly obtuse
Re:Read this post ‘unless’ you’re not a Ruby developer
by moonchrome on Tuesday December 13, 2022 @05:17AM
(#33966823)
God that's such a landmine when reading code. Seeing a return without an explicit change of scope... Why ? To save one line ?
Yep that's why I hate ruby - worked on one mature codebase for a year and after seeing various such gems used across the project - from >10 devs - I'm confident I will never touch the language again.
Re:Read this post ‘unless’ you’re not a Ruby developer
by ilyt on Tuesday December 13, 2022 @09:13AM
(#33969099)
right but
if condition { return }
works well enough in other languages and shows actual condition (the important part) to programmer first. if that if and extra brackets is really too long Perl way is also option.
Re:Read this post ‘unless’ you’re not a Ruby developer
by swat535 on Tuesday December 13, 2022 @05:12PM
(#33976764)
Those are called Guard clauses and they are implement in plenty of systems.. this paradigm has nothing to do with "Ruby".
In any case, the Ruby community already has good guidelines on the "Unless" usage, there are few scenarios where they are useful but it's not like you find them everywhere in a codebase.
For example, we don't use "Unless" with "Else", or use Unless with negation (like the article), or use Unless in nested If statement, etc. Rubocop will catch many of these and warn you.
My point is that experienced engineers will use the language as it was intended to and not abuse its features.
Re:Read this post ‘unless’ you’re not a Ruby developer
by soheil on Tuesday December 13, 2022 @05:36AM
(#33966974)
If you're returning who cares about the scope? Are you saying visually you'd like to have indentation inside the if body? If that's the case there is also nothing stopping you in most languages from doing something as nasty as:
Re:Read this post ‘unless’ you’re not a Ruby developer
by moonchrome on Tuesday December 13, 2022 @05:56AM
(#33967134)
I do because return means end of scope. Except in your example it hides the fact that it's creating it's own scope.
I'm not arguing other languages can't produce bad code, just that ruby is particularly suited for it especially as number of developers working on code increases. I've seen people propose a linter to enforce consistency - but at that point I might as well chose a language with better design choices - plenty of alternatives these days.
Re:Read this post ‘unless’ you’re not a Ruby developer
by multiplegeorges on Tuesday December 13, 2022 @08:36AM
(#33968617)
> I've seen people propose a linter to enforce consistency - but at that point I might as well chose a language with better design choices - plenty of alternatives these days.
You're seriously proposing that adding a linter has the same organizational costs as changing languages entirely. Meanwhile, back in the real world...
Ruby has major advantages over many other languages and a linter is basic tooling you should have in every development environment.
Re:Read this post ‘unless’ you’re not a Ruby developer
by quietbritishjim on Tuesday December 13, 2022 @05:56AM
(#33967125)
I'll admit I'm not a Ruby developer, but wow it allows return conditionally inside an expression? What were the language designers thinking?! I can't think of any other language that allows return inside an expression (or break/continue). Let's see: C, C++, C#, Python, Javascript, Object Pascal, Java, Rust; all nope. That is indefensible.
Re:Read this post ‘unless’ you’re not a Ruby developer
by tsimionescu on Tuesday December 13, 2022 @07:05AM
(#33967776)
You've listed languages that separate statements from expressions in their syntax. There is a whole other family of languages where choose consists entirely of expressions - starting with LISP in the 50s, and including virtually all FP languages today (F#, Ocaml, Haskell, SML, Clojure). Ruby happens to be one a member of the latter group. To be fair, most of the languages in that group don't have an equivalent of return/break/continue either - I think only Ruby and some Lisps do.
Regardless, all of the languages above except C and maybe Object Pascal can still have control stop in the middle of an expression, since an expression can throw an Exception (indirectly). Returning is not significantly different from that.
Re:Read this post ‘unless’ you’re not a Ruby developer
by tialaramex on Tuesday December 13, 2022 @06:49AM
(#33967613)
> I can't think of any other language that allows return inside an expression ... Rust
Er, what?
You understand almost everything in Rust is an expression right?
let x = if yeah_nah() { return 5; } else { "X" };
That return is an expression, obviously we mostly care about the expression's side effect which is a change of control flow to leave the function with some sort of integer 5 as the return value (the function signature tells Rust which kind of integer this 5 is) - but the expression "return 5" itself does have a type, it's ! aka Never, an Empty Type because no values of this type can exist - because the side effect will change the control flow before we need a value.
Rust's type inference engine is fine with this because under type arithmetic all the values fit in a single type, the type of "X" - &'static str - there are no values on the left to disrupt that.
Re:Read this post ‘unless’ you’re not a Ruby developer
by vidarh on Tuesday December 13, 2022 @08:02AM
(#33968279)
It's not doing "return conditionally inside an expression". The above statement is equivalent to:
if !condition
return
end
In other words, the return in question has no argument. The unusual (but not unique) aspect of Ruby here is that if/unless can suffix the "then" block and not just prefix it.
Re:Read this post ‘unless’ you’re not a Ruby developer
by vidarh on Tuesday December 13, 2022 @08:10AM
(#33968355)
This isn't exactly true. It's a syntax error to put a return anywhere where the grammar expects a value expression, because it's one of few constructs in Ruby that doesn't return a value (contrast with e.g. "if" and "def" and "class", all of which return a value).
E.g. "42 == (return true)" is a syntax error while "42 == if false; true; end" is syntactically valid.
You can return in the expression in the comment above because the return is at statement level - nothing above it in the grammar requires a value (but obviously allows it).
Off the top of my head I can't remember which other keywords fall in that category. Obviously "end", "then", "alias" and there'll be a few more, but for most keywords in Ruby you're right they can be treated as expressions.
Re:Read this post ‘unless’ you’re not a Ruby developer
by eyelidlessness on Tuesday December 13, 2022 @04:16AM
(#33966450)
I’m one of those weirdos who can inline a double negative instantly so, I didn’t read it yet but I probably will because I’m curious about the title anyway
Re:Read this post ‘unless’ you’re not a Ruby developer
by eyelidlessness on Tuesday December 13, 2022 @04:21AM
(#33966484)
Oh my dear lord I didn’t think I’d actually disagree with the f’ing article but I had like 8 cases today that made me wish I had a built in if-not keyword! I mean, every language with the billion dollar mistake probably needs a language feature designed to pay back some of that.
Re:Read this post ‘unless’ you’re not a Ruby developer
by sph on Tuesday December 13, 2022 @04:17AM
(#33966457)
The worst thing about `unless` and double negatives, is having been raised in a culture with different double negative rules than English. In Italian a double negative is still negative.
I know boolean logic pretty well, but `unless !something` still trips me up to this day.
Re:Read this post ‘unless’ you’re not a Ruby developer
by codethief on Tuesday December 13, 2022 @05:40AM
(#33967010)
> In Italian a double negative is still negative.
Same in Spanish!
I think you're making a very good point here – understanding "unless" (quickly, i.e. without having to think about it) very much depends on one's understanding of the English language and/or one's mother tongue. Sure, one can probably get used to it (like one gets used to what "if/else" means etc.), but it definitely increases the mental effort needed to read & understand code.
Re:Read this post ‘unless’ you’re not a Ruby developer
by yebyen on Tuesday December 13, 2022 @06:27AM
(#33967423)
I think we're going to have problems if we try to make all languages consistent for users of all languages.
If and unless are English language keywords besides being Ruby keywords; and in Spanish, the word for "if" and the word for "yes" only differ by an accent mark.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hnbad on Tuesday December 13, 2022 @04:41AM
(#33966592)
There are two different kinds of double negatives and English actually has both.
E.g. `I can't get no satisfaction` is structurally equivalent to French `ne ... pas`, i.e the second `no` is a reaffirmation, not a negation.
On the other hand `read this unless you're not a developer` is a logical double negation and thus equivalent to `read this if you're a developer`. In practice of course there are usually implied subtleties that make the two not entirely equivalent (the same way synonyms are conceptually interchangeable but may carry different subtext).
EDIT: I can't actually think of any true "double negative" in English that isn't indirect (e.g. `indirect` being synonymous with `not direct` thus `not indirect` being synonymous with `not not direct` and `not not` cancelling itself out). The only direct forms I can think of behave like `not ... no` in my first example, i.e. re-affirmations of the negative rather than double negations.
I think most of the complaints about "double negatives" (where the Rolling Stones line is usually cited as an example) are stylistic preferences or intentional misunderstandings based on arbitrary prescriptions (which are usually based in other languages like Latin that are perceived as "purer" or "more sophisticated").
Re:Read this post ‘unless’ you’re not a Ruby developer
by tialaramex on Tuesday December 13, 2022 @07:17AM
(#33967892)
The phrase for what's going on in that Rolling Stones lyric is "Negative concord" and yes, it's normal in many languages and that includes a lot of non-prestige English variants.
"Ain't nobody got time for that" is clear, likewise "I didn't go nowhere" and "He ain't take nothing from nobody" and when something is not clear ("That ain't nothing" could mean it is, or it is not, something) context usually suffices.
Re:Read this post ‘unless’ you’re not a Ruby developer
by hnbad on Wednesday December 14, 2022 @07:23AM
(#33982539)
True! But that still falls into what I said about true double negations usually having subtext that justifies their existence. Compare "I don't hate it".
I'd argue that in "I don't not like my hometown" not-liking acts almost as a compound verb, similar to "disliking" (which is just using a Latin prefix to say "not"). Resolving the double negative results in information loss because it omits the subtext (which in this case is the important part of the answer).
In other words, saying "I don't not like my hometown" makes sense because "I don't like my hometown" implies negative emotions (disliking) rather than an absence of positive emotions (liking). The difference could also be conveyed in emphasis ("I don't like my hometown") but this is more subtle and easier to misunderstand.
Re:Read this post ‘unless’ you’re not a Ruby developer
by weatherlight on Tuesday December 13, 2022 @10:11AM
(#33969853)
When I write ruby, and I love ruby, I don't do too much condition branching of logic.
- `if` and `unless` are for guards. The meat of every method, (the happy path) is at the bottom of that method.
- If there are legitimately two options that branch on a conditional, I try to make sure that both branches return the same type. (feature flags, a/b feature testing, etc.)
- If I can refactor code to a case statement, I will 95% of the time
This article screams, "I don't use a linter" or "I work at a company that doesn't have a style guide."
Re:Read this post ‘unless’ you’re not a Ruby developer
by thomascgalvin on Tuesday December 13, 2022 @10:19AM
(#33969978)
I don't write ruby at all, but this is how I write my Java, Kotlin, and Javascript; fail-fast at the top of the method, with the happy path following.
And I'll take it one step further: I see a multi-line branch as a code smell in and of itself. If something in a branch takes multiple statements, I am of the opinion that the body of that branch should probably broken out into a method.
So if we're going off the article title, my code might look something like
val isNotRubyDev = !user.isRubyDev
if(isNotRubyDev) return
// ...read article
Re:Read this post ‘unless’ you’re not a Ruby developer
by clolege on Tuesday December 13, 2022 @05:10AM
(#33966774)
The real problem is that all negatives make it harder to understand things. They open the door for double (and triple) negatives to find their way into the code, and then bang: The only person who can read it is the person who wrote it.
Since unless has a not built into it, it has a lot of potential to confuse people. In my experience, guard clauses are the only place where they make sense.
def mute_mic
return unless mic_active?
..
end
In this sense, you know that the entirety of the function is an expected (positive) case.
Re:Read this post ‘unless’ you’re not a Ruby developer
by thunderbong on Tuesday December 13, 2022 @07:51AM
(#33968193)
IMHO, 'unless' in Ruby works best for single checks. It's just a convenient form of 'if not'. That's about it.
I always insist on not using 'unless' if it's not clearly readable as an english phrase or if there's an 'else' as well.
A similar pattern I follow with 'if !'. If there's an 'else' condition always put the positive check first and the negative one in the else, rather than the other way around.
Footguns are equally possible using complex 'if !' statements.
Re:Read this post ‘unless’ you’re not a Ruby developer
by 3pt14159 on Tuesday December 13, 2022 @09:26AM
(#33969287)
There are two main reasons unless is great and I miss it now that I primarily program in python.
1. It is a negative, and that is a great thing when there are boolean conditions. Yes, you can wrap the whole thing in brackets, but when doing a visual scan quickly over code, they're easier to miss than the giant `unless` token which guarantees that you won't have an early closing bracket. The more the number of terms go up, the more I have to be fastidious with watching where brackets begin and end.
2. It hints to the expected flow of things. Isn't the first more readable to you?
return :allow_air_travel unless self.nuclear_war_ongoing?
return :allow_air_travel if ! self.nuclear_war_ongoing?
Or I'll put it another way. If you do a search of your own hacker news comments on BigQuery, will you never find the english word "unless" outside of a Ruby discussion there? You could say "if not" why bother using an extra word? Or what about "not true" do you ever say that when you could just say "false" like Dwight from The Office?
Re:Read this post ‘unless’ you’re not a Ruby developer
by locallost on Tuesday December 13, 2022 @10:27AM
(#33970088)
My guess is what's putting me off on unless is the baked in negative. If I look at a condition and imagine "if true" I can follow along, but "unless true" makes me think "what does that even mean". Another issue might be that not everyone is a native english speaker (like me), and that we underestimate that thinking in boolean logic might not be the most natural thing in the world, and once you learn it, you usually learn it in a foreign language. Substituting "if !" with "unless" just throws a wrench in the patterns you're used to using.
I disliked it as well in CoffeeScript. The use of else blocks is especially annoying, but even otherwise I don't like it. Some might say you shouldn't use it with an else block, but this is not realistic if you work in a team.
Re:Read this post ‘unless’ you’re not a Ruby developer
by drewbug01 on Tuesday December 13, 2022 @07:39PM
(#33978439)
Alas, it seems I've missed my chance to discuss one of my favorite things: Ruby. If you're a latecomer to this submission like myself, here are three things to keep in mind as you read the replies:
- Many remarks concern the difficulty of understanding "unless" for those with a first language other than English. It may be interesting to note that Ruby was created in Japan, and that "unless" has been in the language since the very first release. [1]
- Matz has a very interesting and famous quote about the principle of least surprise: "it means the principle of least surprise after you learn Ruby very well." [2]
- Computers don't care how programs are structured. Businesses don't care how systems are architected. The canvas does not care how paint is applied. Software engineering is an art. [3]
Re:Read this post ‘unless’ you’re not a Ruby developer
by 1123581321 on Tuesday December 13, 2022 @05:09AM
(#33966770)
statement unless condition is a wonderful bit of syntactic sugar. It reads like natural English if the variable or method it is evaluating is named well.
Yes, sometimes you have to refactor into a traditional if. Sometimes you make the conditional its own method (which you’d end up doing anyway, assuming it didn’t stop at two or three conditions.) These are light tasks as the project grows.
Starting a line with unless, on the other hand, does not work for me. It is also awkward in short English sentences. And long English sentences, where beginning with unless is more appropriate, don’t have analogies in single-line ruby statements.
Re:Read this post ‘unless’ you’re not a Ruby developer
by 1123581321 on Tuesday December 13, 2022 @11:15AM
(#33970843)
Don’t you know the word after awhile? Ruby core and standard libraries have many English words in them that are harder to learn than basic one-syllable words on the level of “if not.”
Re:Read this post ‘unless’ you’re not a Ruby developer
by dgunay on Tuesday December 13, 2022 @05:21AM
(#33966849)
In Perl you can write postfix conditionals: `thing() unless $condition`, which at least is more natural usage of "unless" to a native English speaker than the other way around. That's the best way to use it IMO.
This also align well with the lake of scalability of the number of condition: I doubt that in usual prosaic English its common to use "unless first-condition or second-condition or … ultimate-condition".
Of course it is logically equivalent to `if not`, but it is pragmatically not conveying the same information at human interpretation level.
Re:Read this post ‘unless’ you’re not a Ruby developer
by masklinn on Tuesday December 13, 2022 @04:16AM
(#33966452)
I don’t disagree with the essay, and I do generally dislike “unless” as it’s a cutesy statement which does not pull its weight (it would probably be better if there was no “else” clause at all).
However I find some of the examples / justifications unfortunate e.g.
> I find the second option less readable because it suggests that raising the error would be the normal thing to do, when in fact it’s the exceptional thing to do.
It’s not tho. The normal thing to do is to reject access, being an admin is exceptional. A restricted endpoint should absolutely assume the user is not authorised.
Re:Read this post ‘unless’ you’re not a Ruby developer
by dkdbejwi383 on Tuesday December 13, 2022 @04:25AM
(#33966499)
Fair enough argument for that particular example, but I think the author's point still stands for the other example (if !user.suspended do send_email end)
Re:Read this post ‘unless’ you’re not a Ruby developer
by uticus on Tuesday December 13, 2022 @09:42AM
(#33969462)
Ruby is an interface between at least three realms: the human (typically English conversant), the machine (instruction-based), and logic.
Not unique and not the best, but popular and usable enough to be fascinating for anyone who's given more than passing thought to how difficult it is to communicate in any one realm separately (let alone across realms).
For example, I had a meeting with POs recently where it took an hour to communicate a concept in English and distill a logic diagram from it. I'm not placing blame on English (although some would [1]), POs, or myself. It's just common experience that communication is difficult.
Personally I always enjoy flexibility and expressiveness when writing (English or code), usually when reading (English or code), and sometimes when debugging (English or code). So I like Ruby pretty well. YMMV.
Re:Read this post ‘unless’ you’re not a Ruby developer
by klooney on Tuesday December 13, 2022 @10:13AM
(#33969886)
Unless and ternaries are great signals in a pull request that you should build a truth table and double check it. They're backwards all the time, especially in less tested, error handling codepaths.
Re:Read this post ‘unless’ you’re not a Ruby developer
by asdajksah2123 on Tuesday December 13, 2022 @10:35AM
(#33970192)
ternaries are expressions.
Just because of that they are far superior to if/else/unless, unless ;-) you're using the ternaries to execute statements with side effects instead of just returning a value.
Re:Read this post ‘unless’ you’re not a Ruby developer
by makoto12 on Tuesday December 13, 2022 @04:38AM
(#33966573)
I've written ruby everyday for the past 5 years. I still cannot read an unless statement and understand it first time. Most of the time i'm translating it to `if !` anyway.
Re:Read this post ‘unless’ you’re not a Ruby developer
by zelphirkalt on Tuesday December 13, 2022 @07:50AM
(#33968184)
Ruby is not the only language with "unless", actually. For example it exists in GNU Guile as well (https://www.gnu.org/software/guile/manual/html_node/Conditio...). However, due to the usual structure of functions and the last expression being the return value, one always expects a return value (why else call the function?). So "when" and "unless" are only seen inside procedures, which have side effects.
Re:Read this post ‘unless’ you’re not a Ruby developer
by fl_ciq on Tuesday December 13, 2022 @09:32AM
(#33969353)
Unless seems to be pretty common in many languages. https://www.indifferentlanguages.com/words/unless In my mind the javascript community would do well to address the idiosyncrasies in its language standard before criticizing other languages for using common human language patterns. If you want to pick on ruby for being weird with conditionals, consider the following.
if 0
puts 'true'
end
which will print true. I think there is a much greater chance that 0 being true will cause problems with programmers from other languages than using unless which is quite natural to humans. Ruby is first and foremost a language for humanity, and probably dead last a language for ease of implementation.
> As a general rule I think that if a language has some feature for which there is already a commonly understood syntax across other languages, it should just use that syntax. If you’re introducing a complete paradigm shift, then that’s fine, but unless is not that: it’s just a different way to write if ! and people jumping back and forth between ruby and, say, javascript, now have one extra idiosyncracy to keep in mind.
Re:Read this post ‘unless’ you’re not a Ruby developer
by fl_ciq on Tuesday December 13, 2022 @04:14PM
(#33975899)
Thanks for that, I had no idea. Do you know if zero is truthy in erlang? It makes sense for elixir (based on ruby) but I'm wondering if erlang is that way too.
Re:Read this post ‘unless’ you’re not a Ruby developer
by beeforpork on Tuesday December 13, 2022 @02:30PM
(#33974421)
How about 'ifnot'?
Although I like 'unless' in Ruby, Perl, CommonLisp (sometimes a condition is just naturally the other way of how 'if' wants it), I acknowledge that people get emotional and really hate it. Maybe a better alternative would be 'ifnot' to avoid the ! operator and the parentheses.
Re:Read this post ‘unless’ you’re not a Ruby developer
by aidenn0 on Tuesday December 13, 2022 @03:08PM
(#33974973)
Common Lisp has an unless macro, but it lacks an else clause, implicitly taking the value "nil" if the test expression is true. It's probably most useful for aborting the flow of the code, e.g.:
(unless foo (error "Foo should not be nil"))
In less functional code, you sometimes see it for default values (though "OR" seems to be more idiomatic for that case):
(unless foo (setf foo 3))
Regardless it has few of the downsides that TFA mentions (the sole exception being introducing a double-negative for unplanned compound test statements), but I don't find something like
(unless (and foo (not bar)) (error ...)))
To be that unclear; we want both "foo" and "!bar" or error.
Re:Read this post ‘unless’ you’re not a Ruby developer
by lamontcg on Tuesday December 13, 2022 @12:21PM
(#33972124)
Use rubocop. Ban the use of `unless` except as a trailing conditional and ban double-negatives. Then the only thing you can do is `foo unless whatever?` and if someone comes along and modifies that to something horrible rubocop will yell at them that it is horrible (and `rubocop -a` will auto-fix it).
Re:Read this post ‘unless’ you’re not a Ruby developer
by bryanrasmussen on Tuesday December 13, 2022 @08:07AM
(#33968323)
on a project about a decade ago I had written some ruby code in a non-rubyish manner (non-rubic?) in that I had written if statements.
I had actually decided to write them as if statements because that way I didn't have to make one particular logical check (I can't really remember what the logic was, just that it had to do with language and Swedish language legal documents did not have a particular rule that Danish ones did.
So a senior Ruby dev who admittedly was a lot better than me in a lot of things but did have the habit of making incredibly boneheaded bugs sometimes, went through and rewrote all my if statements as unless statements - inadvertently reversing the logic.
A week later bug comes up I get blamed because it was the thing I worked on I was embarrassed, and I went through the code fixing but then I thought - wait I wouldn't have written this as an unless because I need to do one extra statement that way! After digging through I caught our senior dev, the very guy blaming me for causing bugs.
Re:Read this post ‘unless’ you’re not a Ruby developer
by ricardobeat on Tuesday December 13, 2022 @09:31AM
(#33969342)
That's a lot of words for a simple matter of cleanliness. Do not use 'unless' for complex expressions, only single conditions. I personally hate grouped negatives like the one shown:
!(valid_token && !expired)
This expression is also a double (triple?) negative, and a lot harder to parse. The correct approach is to make the `valid_token` flag take `expired` into account, or add a third variable that represents validity, not append `expired` to the unless clause. This keeps everything readable, if the variable names are descriptive enough:
It's also damning that the author uses `unless ... else` as his starting point for the critique, while he is aware that the style guide says "Do not use unless with else" (briefly acknowledged in the last section).
Re:Read this post ‘unless’ you’re not a Ruby developer
by corytheboyd on Tuesday December 13, 2022 @09:47AM
(#33969522)
You can contrive bad usage of just about anything in any language. Nobody actually writes "unless ... else". The few times it's come up it's been shot down in code reviews. unless is still perfectly fine for simple one line statements though.
Do I think Ruby NEEDS unless? No. Does this keep me awake at night? No lol
Re:Read this post ‘unless’ you’re not a Ruby developer
by hk1337 on Tuesday December 13, 2022 @05:57AM
(#33967140)
It’s a bit awkward to grasp initially but personally I like it. I don’t wish it in all languages but it works in ruby. It especially works well in templates and checking collections.
Honestly, I find negative checks like `if !something` ugly, I would much rather check if the result is true than !true. The same with unless, I would prefer to check unless false than unless not false or unless !false
Re:Read this post ‘unless’ you’re not a Ruby developer
by quietbritishjim on Tuesday December 13, 2022 @05:26AM
(#33966890)
Well I really showed myself up as commenting on a topic that I know nothing about! :-)
But that's actually ideal in this context, a really low precedence operator is exactly what you want because you can swap `unless` for `if not` without worring about extra parentheses:
send_email if not user_suspended? || user_opt_out?
Re:Read this post ‘unless’ you’re not a Ruby developer
by greenpeas on Tuesday December 13, 2022 @06:55AM
(#33967677)
I wouldn't use this. Relying on tricky operator precedence can trip up your readers. It's better to just wrap everything in parentheses.
I also use parentheses when mixing && and ||, even though their precedence relationship is (probably) more widely known.
Re:Read this post ‘unless’ you’re not a Ruby developer
by forkerenok on Tuesday December 13, 2022 @05:10AM
(#33966772)
Funny, when I read your point, I was sure and ready counter with an argument that code editors must highlight symbols and unary operators differently (colours, maybe spacing as well). But I just checked this on a couple of Ruby and JS highlighters and they are actually not! :scream:
Re:Read this post ‘unless’ you’re not a Ruby developer
by Joker_vD on Tuesday December 13, 2022 @06:43AM
(#33967554)
The "logical negation" sign used to have the vertical line as long as "|", so e.g. "¬A" looked more like "‾|A" but fully vertically aligned with the letter. Sadly, this glyph fell out of usage in fonts in favour of "minus with cedilla/descender".
Re:Read this post ‘unless’ you’re not a Ruby developer
by jjgreen on Tuesday December 13, 2022 @10:25AM
(#33970060)
I'd always understood it came from Frege's Begriffsschrift, a small descender from a horizontal line (part of a larger diagram), so like a short wide T, then lost its right arm later. Would you have some examples? (a quick google images shows nothing like that ...)
Re:Read this post ‘unless’ you’re not a Ruby developer
by Joker_vD on Tuesday December 13, 2022 @09:42PM
(#33979381)
It was definitely a thing in Soviet works on mathematical/symbolic logic. But here's an example from Curry [0]. As I said, it was mostly a stylistic choice.
Re:Read this post ‘unless’ you’re not a Ruby developer
by OliverGilan on Tuesday December 13, 2022 @10:46AM
(#33970376)
I actually completely agree with the author. I remember coming across my first unless statement while trying to find the source of a nasty bug and I spent probably 5 minutes just trying to decipher the behavior of the unless block because my brain had some roadblock with the double negatives. This has become a lot easier to understand as I’ve used Ruby more but it still seems like a massive opportunity for cognitive complexity and errors for little gain
Re:Read this post ‘unless’ you’re not a Ruby developer
by inerte on Tuesday December 13, 2022 @06:54AM
(#33967656)
I used to write my if/else like the author advocates. The "true" condition first, followed by the "false".
A long time ago, a friend code reviewed and asked me to change to the most common condition first, as advocated in the Code Complete book (which I hadn't read at the time).
I still think it reads better if/else as true/false, but I am also big on having standards and a coding style, even if I disagree with them.
I mean, unless there's a lack of coding standard I will follow it.
Re:Read this post ‘unless’ you’re not a Ruby developer
by quickthrower2 on Tuesday December 13, 2022 @05:52AM
(#33967102)
I take issue with the word unless. "Un" means opposite and "Less" means, well less, so unless means more. So `unless` should just be a straight alias for `if`.
Re:Read this post ‘unless’ you’re not a Ruby developer
by _moof on Tuesday December 13, 2022 @06:36AM
(#33967496)
The "un" in unless isn't the negating prefix "un-"; it's the word "on" with a change of vowel. The etymology is "on less[er condition than]," e.g., "Abort the launch on less than the rocket is deemed safe to fly."
Re:Read this post ‘unless’ you’re not a Ruby developer
by lucidone on Tuesday December 13, 2022 @09:00AM
(#33968911)
I'm not a very experienced Ruby developer but RuboCop does a pretty good job at guiding and teaching you to use `unless` as a guard in method definitions, e.g.:
def my_method(required_thing)
raise 'required_thing is required' unless required_thing.present?
...
end
In practice, this hasn't been as issue as a consequence of the tooling and ecosystem around Ruby.
Re:Read this post ‘unless’ you’re not a Ruby developer
by lucidone on Tuesday December 13, 2022 @10:13AM
(#33969882)
I don't think it's a problem necessarily. "unless" is more obvious to me since since it visually stands out more than "if !required_thing" while I'm casually scanning the code. So, in practice, it acts as an indication from the author of the code to the reader that "this line of code is a guard since we're using an unless".
Re:Read this post ‘unless’ you’re not a Ruby developer
by codegangsta on Tuesday December 13, 2022 @03:17PM
(#33975119)
I find `if not` to be a far superior version, simply because it reads similarly to it's `if` counterpart, specifically for how conventionally condition methods are written in ruby.
`return if not valid?`
or
`return if invalid?`
Both make sense in my brain, whereas
`return unless valid?`
Feels like I need to make another connection to understand it
Re:Read this post ‘unless’ you’re not a Ruby developer
by gmiller123456 on Tuesday December 13, 2022 @09:50AM
(#33969564)
I work with so many languages on a regular basis, I specifically avoid such language features, I won't even use the x if y syntax. My cognitive effort is better spent memorizing other specific things about the language.
That said, I think the author is overselling the need to not use such features. Despite my aversion to using such features, I have no problem reading them.
Re:Read this post ‘unless’ you’re not a Ruby developer
by schneems on Tuesday December 13, 2022 @03:23PM
(#33975188)
I used to love unless, but now I prefer `if !`. Sometimes when I read `unless` i manually make the conversion in my head. The only problem i've run into is standardrb thinks otherwise and I've not mustered up the energy to bikeshed that change through.
Re:Read this post ‘unless’ you’re not a Ruby developer
by celeritascelery on Tuesday December 13, 2022 @11:53AM
(#33971533)
When I see unless in the prefix position (unless x then y) I have mentally read it twice. I reread it as `if not` because otherwise my brain can’t grok it. But if it is in the postfix position (y unless x) then it is super easy for me to grok. I think that is because how we would use it in natural language.
Re:Read this post ‘unless’ you’re not a Ruby developer
by davesque on Tuesday December 13, 2022 @03:04PM
(#33974911)
I've always felt that language features like 'unless' in Ruby and also things like 'on' and 'off' in Coffeescript fall squarely into the category of too clever. Simplicity will always win until the end of time.
Re:Read this post ‘unless’ you’re not a Ruby developer
by vidarh on Tuesday December 13, 2022 @03:23PM
(#33975193)
To me your two statements here are in conflict with each other. I use "unless" in Ruby when it leads to simpler code. That ability to write code which reads simpler is its sole reason for existing.
(the headline however, is an exceedingly bad example)
Re:Read this post ‘unless’ you’re not a Ruby developer
by jbaber on Tuesday December 13, 2022 @06:58AM
(#33967699)
It's a matter of taste.
I find inheriting code riddled with witty logic puzzles distasteful, so prefer my predecessor to have written Python, which constrained them from crafting too many.
Some people want a project to be a series of cryptic crosswords. For them perl/ruby/C.
When I write perl/ruby/C, I restrain myself from filling it with cool puzzles, but I usually don't get to inherit code from myself.
Re:Read this post ‘unless’ you’re not a Ruby developer
by davedx on Tuesday December 13, 2022 @07:00AM
(#33967716)
I mean this is `ruby` for you, this is one of its principles, providing more than one way of doing something and making that thing "ergonomic and pleasurable". I don't think many devs who choose to use ruby would want to proscribe things like unless?
Re:Read this post ‘unless’ you’re not a Ruby developer
by sod on Tuesday December 13, 2022 @04:59AM
(#33966710)
Without syntactic sugar that differentiates a language from another, I see no way for a new language to become popular. So while some decisions may seem confusing, they helped gathering interest. IMO ruby and python became so popular because of their quirks.
Re:Read this post ‘unless’ you’re not a Ruby developer
by 0x457 on Tuesday December 13, 2022 @01:19PM
(#33973294)
hmm, you're doing `unless` with `!` in condition you're doing it wrong.
unless user.has_errors?
user.save
end
IMO better than `if !user.has_errors?`, at least for me: I will read it as "unless" in my head even in languages that only have `if`. You know what? I will just start using `unless` even harder, I will even make a rust macro for that.
Re:Read this post ‘unless’ you’re not a Ruby developer
by gexla on Tuesday December 13, 2022 @04:29AM
(#33966522)
Just to help people out. If you can't write out the title as a conditional statement in Ruby, you're not the intended audience. Though it still may be interesting as a discussion in conditionals in general.
Re:Read this post ‘unless’ you’re not a Ruby developer
by ndsipa_pomu on Tuesday December 13, 2022 @06:00AM
(#33967168)
Reminds me of my pet hate in user interfaces - having a check box for a negative condition such as "disabled" rather than having "enabled" and changing the default state of it.
Re:Read this post ‘unless’ you’re not a Ruby developer
by kazinator on Tuesday December 13, 2022 @12:12PM
(#33971899)
common-lisp has functions called remove-if-not (applicative) and delete-if-not (destructive version).
The spec says that [t]he functions delete-if-not and remove-if-not are deprecated.
But all that is wrong is their double negative name. remove-if-not is precisely the same thing as keep-if, which is too useful to deprecate. Numerous languages have a function like this, sometimes called filter or similar.
Re:Read this post ‘unless’ you’re not a Ruby developer
by twic on Tuesday December 13, 2022 @12:14PM
(#33971940)
So:
> Read this post ‘unless’ you’re not a Ruby developer
But:
> Read this post if you’re a Ruby developer
Surely?
Seriously though, the main way Ruby went wrong was an obsession with this entirely superficial kind of expressiveness and simplicity. Rubyists will lard their code with all sorts of "convenient" and "easy" features, to save a few keystrokes here and there, at the expense of bloating their APIs and hiding weird, hard-to-reason about magic.
Re:Read this post ‘unless’ you’re not a Ruby developer
by shortcake27 on Tuesday December 13, 2022 @06:04AM
(#33967207)
`unless` is generally used for guard clauses (eg `return unless authorized?`) or when there’s only one branch. You don’t tend to see `unless` used with multiple branches.
Re:Read this post ‘unless’ you’re not a Ruby developer
by soheil on Tuesday December 13, 2022 @05:08AM
(#33966762)
"Unless" should only be used when the imperative condition is simple.
You don't understand Ruby if you think there is something wrong with trying to have more than one option to do things, imperfect shortcuts and more human-readable code.
Unless works really well when there is one named boolean variable after it and it's named correctly or if the condition is simple to understand.
It also works well when used inline and without an else statement. For other cases "if" is better-suited. But then again "unless" is another option in your tool chain that makes for a more elegant programming language if you're not a stickler and not constantly finding yourself pining for a platonic language.
user = User.find(2000)
return unless user
It'd be easier to miss the "!" character in the case of "if !".
Re:Read this post ‘unless’ you’re not a Ruby developer
by phplovesong on Tuesday December 13, 2022 @08:25AM
(#33968487)
Many languages try to be too cute. I was just reading up on the newish "Roc" language. There i saw List.dropIf and List.takeIf, thats basically just filter with a slipped bool check.
Re:Read this post ‘unless’ you’re not a Ruby developer
by Karunamon on Tuesday December 13, 2022 @08:26AM
(#33968501)
Ask the people who blindly apply and enforce Python pep8 which assumes everybody is on an 80 column glass terminal in the age of throwaway PCs having 16:9 screens.
Re:Read this post ‘unless’ you’re not a Ruby developer
by rodgerd on Tuesday December 13, 2022 @03:42PM
(#33975436)
The whole premise - that double negatives don't work for humans - is invalid. Natural languages have and continue to make use of double negatives and double positives (and in some cases, the positive-negative).
Obviously if your specific language doesn't make use of it, or makes use of it in a different way to ruby (e.g. is your natural language treating the second negative as a negation of the negative, or an intensifier of it?) then ruby's grammar will seem unnatural. But that's going to be true for anyone who's trying to map their natural language onto a programming language whose grammar is different to theirs.
Re:Read this post ‘unless’ you’re not a Ruby developer
by anm89 on Tuesday December 13, 2022 @01:54PM
(#33973885)
I've been doing Rails for 10+ years and `unless x` absolutely breaks my mind. I have to internally convert it to `if !x` and evaluate it in my head 90% of the time.
Re:Read this post ‘unless’ you’re not a Ruby developer
by dimitrios1 on Tuesday December 13, 2022 @10:45AM
(#33970353)
As you learn more programming languages, these cute little operators become less cute and appealing, as you realize that !condition would be far more ubiquitous and transferable than something like unless condition.
I "grew up" in my career as a rails dev myself, but I favor things that are immediately clear to the broadest amount of people possible these days. And if you truly miss these constructs, in any language where you have metaprogramming, which is most these days amongst the broadly used ones, it should be trivially to implement them, should you insist on continuing to use them.
I use Elixir for my "fun" language these days, and they provide unless/2 as a macro, (if/2 is also a macro), but I haven't found myself reaching to use it once.
Why? Because it allows you to express yourself more elegantly.
The click-bait title is misleading. It's meant to ridicule "unless", but actually achieves the opposite.
If you were to write the title of the post as code, it would be:
That would be a terrible use of "unless"! That should clearly say "if ruby_dev", not "unless !ruby_dev".But what if you wanted to write an article meant for anyone other than ruby developers?
Which of the following is better?
or Both work, but I consider the second option more elegant. Just as I wouldn't verbally say "if you're not a ruby developer" rather than "unless you're a ruby developer".Honestly, I don't see the issue. It's a style matter. Just use it properly. All language can be abused if you try hard enough.
This is not a contrived example. I regularly find myself having to read some code in a language in which I am not proficient. Stuff like ’unless’ is such a pointless obstacle in these scenarios.
So ”elegance” doesn’t come free. The cost is a loss of transferable knowledge from other languages. Your intuition is that this cost is low relative to the benefit of ”elegance,” I have the opposite intuition. Why stray from such universal conventions in favour of one person’s subjective aesthetic preference?
And if you go on that direction, almost the everything on the language is a larger roadblock than an oddly placed conditional.
What do you think is more important: the speed at which C programmers can navigate your code base, or one person’s subjective idea of ”elegance”?
Specifically about Ruby, with it's infinite levels of metaprograming and "you can even redefine the meaning of blank space" philosophy, it's not 'unless' that will stop anybody.
That said, when reading code, I often have to pause and mentally translate "unless" to "if not". This is especially true for more complex logic.
Elegant, yes. Additional mental overhead at times, certainly.
You say there is a difficult time transferring knowledge from other languages when they see the `unless`. That's fair.
My response to that is that, to idiomatically think in Ruby is write code that reads well, and `unless` fits that. Every language has an idiomatic way in which one thinks and reasons with the language. While there are principles that can be transferred over across languages, the way to think in that language does not necessarily transfer. The Ruby community has a heavy emphasis on creating embedded DSLs that seems natural enough to written English, and the Ruby community's style guide is written for that.
In contrast to Ruby, Python has idioms that seem to be the inverse of Ruby. The intuitions on what is good, idiomatic Ruby is counter-intuitive in Python. This even extends to the design of Ruby bundler vs. Python virtualenv/pip. As a long time Rubyist, Python rubs me the wrong way (what is intuitive in Python is counter-intuitive in Ruby) until I realized that I used to write that style of code a long time ago with Pascal.
I do like `unless` in Ruby, but only when it is the one liner form and the exception happens pretty rarely. The multi line form often takes a lot of effort to parse for me if it is more than a very simple expression.
Python exposes those methods. What you see is what you get. Classes and objects are not considered as autonomous agents so much as data structures bound with functions that can operate on it.
More controversially than “unless” is Ruby’s way of calling an anonymous function. Almost every other language, if “f” is a function, you can call it with f(). In Ruby, an anonymous function is an object, and you call it by sending a message “.call()”; the shorthand for “call” being “f.()”. Everything is an object.
This trips up even polygots who like Ruby. But if your mind can shift in such a way where that is ever seen intuitive, then you’re probably well on your way to being able to think in Ruby. (Assuming someone _wants_ to think that way).
I want to suggest a slight reframing: instead of saying: "It is not all about cost-benefit," you could say "here is an addition to the 'benefits' column that hasn't been considered yet."
It's a totally reasonable argument; much better than "elegance." This was my main problem: that the critique of `unless` was much more plausible than the defence.
However, we don’t always make decisions purely on cost vs benefit. Some types of decisions, such as strategic thinking, involves unfair advantages. If cost-benefits are reasoned from a finite space in which one can find the optimal choice, unfair advantages cheats that, and operates on a potentially infinite space with imperfect information.
Not that I am saying Ruby or Python are unfair advantages :-) I’m just saying that cost-benefit is not the only way in which one can decide on something, and may not be appropriate for every situation. Being able to think in a language can potentially change how you think, and framing that as a benefit can be problematic.
I explored Ruby because I wanted to explore eloquence, semantics, and pattern languages (in the Christopher Alexander sense). I spent over ten years on it until I had my fill. Now I am exploring concurrency, reliability, uncertainty, self-healing and distributed systems — Elixir and Kubernetes. And while I still use Ruby in some tooling, it doesn’t give me the joy that Elixir does.
A statement that forces you to switch out of inaccurate skiming mode is insanely useful
Practically speaking, that's not how I know Ruby to be written. The convention I follow is to use `unless` when there is no `else` case and only when there is no negation in the expression.
I do wonder if it's an issue of "unless" being misused? Programmers using it just for fun rather than considering whether it's the best choice in context?
When I come across an `unless`, I can't use them; I have to come back out into "conscious reading" mode, or something like that. Makes me crazy.
Problem with so much syntactic sugar is you need to retain/recall the semantics of the vocabulary. As a polyglot programmer who doesn't write much code anymore, it slows me down.
Anything else (at least for me) is more difficult to read, it's probably due to being exposed to all thos other languages that do not have that syntactic construct. Using C syntax conditionals feels more natural to me, but again this is all opinionated.
That said, I feel it's really down to double+ negation being hard to handle. `if` with a single negation is fine; `unless` is automatically a negation, so you're just off to a bad start on that front. I feel like the only viable use is in a case like Rust's `let … else { diverge }` where anything that fails the condition is guaranteed to diverge (typically, return) and I can just ignore it when reading the overall codeflow. But Ruby mixes that up and does `diverge unless …` which puts the diverging part "up front" and "in the way" for such readings.
Weirdly, Ruby was one of the first languages I learned early in my career, and at the time I had no problem with `unless`. But after years of experience with other languages, I similarly feel that `if` statements now trigger the fast pattern matching circuits in my brain, while `unless` makes me do a double-take and basically translate it into `if not`
At first I thought I was just becoming dumber with age, but I like your explanation better :P
When I write Elixir, `unless` gets awkward in a functional style of programming, and Elixir has guard clauses and pattern matching. I pretty much never use `unless` in Elixir despite using it in Ruby for years.
Sometimes, I'll add extra methods with a negation in the name itself. So for example
THING if logical condition
Filter First is far better self-documentation: if condition THING
When I started writing these as pipeline execution. Then I’ll use a maybe?() instead if the conditional does not need to depend on the result of a previous operation.
For example, I can totally see how imperative-first would mess up people with neurodivergant brains.
Tangent -- Ruby takes a lot of inspiration from Perl.
The truth is there is a balance in all languages. Nearly every word was invented to prevent having to say a string of other words to mean the same thing.
"Unless" is a single word to mean "If not". I consider that elegant.
However, some languages take this too far, in my opinion. German famously has a word for nearly everything. I'm not sure that's elegant, in that it requires learning a far greater number of words.
English has many words that I wouldn't consider elegant, simply because they're uncommon or convoluted. Never use a 10 dollar word when a 5 cent word will do.
So, if, like me and the ruby community, you prefer to optimize for developer happiness, "unless" is an elegant choice.
If you prefer to optimize for peak computing performance, if may be more computationally efficient use "if not".
But, _unless_ you're saying that you never use the word "unless" in everyday language, I think we can agree it's a good word that has good applications. I don't see why that wouldn't be true in programming.
That's not quite how it works though, right? Compound words are exactly that, combining two or more words to narrow down the meaning, without having to invent a new word. It's almost like "if not" vs "unless"...
Side note: ancient Greek didn't use spaces, and many other languages (Thai and Written Chinese are the ones with which I'm most familiar) either don't use spaces or make spaces optional. The distinction between a phrase and a word gets a bit blurry at times, and I find the distinction is seldom useful, particularly when making comparisons across languages.
Ruby inherits the Perl philosophy of "There's more than one way to do it". Compare with Python, and its "There should be one — and preferably only one — obvious way to do it."
It's true that it makes the compiler less elegant, but Ruby optimizes for the programmer at the expense of the compiler.
"count" is only equivalent to "length" and "size" when called with no argument and no block, and should be slower for that case (it includes a comparison of arity and a call to rb_block_given_p() in MRI before it returns the array length).
IMHO, something ‶elegant″ in programming is not something that can't be built form something else (or we will all end up in writing only CMOVs), but something that conveys the meaning of its author precisely and concisely – which makes it inherently subjective. I'm in the `unless` team, I can perfectly understand if you are in the `no unless` team, but this argument does not make a lot of sense.
The very ergonomic solution to map a computation to every element of a sequence is `map`. In this case, `for` is filled with bookkeeping that does not matter.
Also, the `for` operator definitely predates the `map` function. Some people also prefer `map` to be more or less pure and expect it to return a usable list; `for ` has no such expectation, it e.g. may consist solely in printing elements.
And `CAS/Compare Accumulator with Storage` definitely predates `if`, still you are most probably using the latter.
But there are enough people on this thread who feel differently that it makes me wonder if maybe we're wrong. If code is meant to be read and understood by all, and if "unless" is confusing to a large number of people, maybe those of us who like it should knock it off.
I do find it more elegant and easier to read, but maybe you and I can process double negatives easier than the anti-unless crowd are able to process "unless" logic.
If that's the case, I'd be willing to sacrifice my preference for "unless" for the greater good.
Could you give an example of a double negative in this case?
I ask because using "if" does not lend itself to double negatives in my experience, but just thinking about "unless" I see double negatives being an issue (since unless is already negating the operand).
I would likely not be a programmer if it weren’t for Ruby and it doing things different.
I had tried to learn programming for years (JavaScript, Python, Java, C#), none of it stuck or progressed beyond following tutorials and one of the things I had serious issues with was negation.
Then I came across Ruby and it just kinda clicked into place like no other language had. With Ruby I was able to do my own things within a month.
Now I don’t really have a problem picking up other languages anymore. But there’s others out there right now struggling to learn programming and there should be as many programming languages doing things different as possible to increase the chance that they come across one that is obvious for the way they think.
This idea of there should only be one way of doing things is poison in my opinion.
Which is why unless is such a hard concept for people to grasp, not just in code, but also in regular English.
At least the "if not" makes the negation explicit, which can then be easily eliminated using several different techniques (early return, swap with the else condition) if the negation is confusing enough.
However, "unless" necessarily includes negation because that's how the word is defined.
This is the first I've heard about this confusion over the word "unless" in English.
In spoken English I do notice that most often the "unless" comes after a statement. Example: "I'll be there on time, unless the bus is late." That is more clear (to me) than "I'll be there on time, if the bus is not late." Maybe not by coincidence, I tend to like "unless" when it follows the action in in Ruby code, too.
Go to the store and get milk, if not we already have some.
I confess at first I thought they were somewhat superfluous, but they are more readable now that I'm used to them. Completely agreed on it being stylistic, mainly.
Sure, I understand the "elegant" aspect, two symbols are shortened to one (although I'd argue that's not that important when it comes to clarity and legibility).
But every time I read "unless" in code it's quite jarring. I have to consciously translate it to "if not", and even then seeing the "unless" keeps tripping me off, perhaps because it's awkward in English to start a sentence out of the blue with "unless".
The `unless` keyword makes the interpreter slightly more complicated and is another piece of language the human brain needs to recognize. It may seem inconsequential, but grains of sand make a hill, as they say.
My ideal language would leave out pretty much anything that can be achieved with more basic constructs. It would of course have if-else, and leave out `unless`, but there would also be no switch statements or ternaries. Branching must be done with if-else or by looking up a value in a hash. No `for` or `while` loops because a simple `loop` construct with `continue` and `break` statements can do everything that `for` and `while` could do in other languages. No classes or inheritance because they're magical and they can be effectively simulated by the end developer if that's what they really want.
What I think would be really cool is to have a language with a syntax like Ruby but with only the most basic of programming language constructs.
You can simulate the loop behaviour if that's what you really want
Structured programming is, I believe, a good idea for the vast majority of use cases. Though one can technically use structured programming while using goto, encouraging goto can therefore allow programmers to go down a path that is counterproductive. It's basically the opposite end of the spectrum from OOP where encouragement of rampant objectiveness and inheritance makes programmers write code that is way too complicated.
There's absolutely a place for goto. I once made a "language" (actually YAML) specifically for developing for the Amazon Alexa platform, and it used something similar to goto called "go to scene" and "go to random". For that sort of thing, goto can be much more practical and even easier to reason about than "better" constructs in general purpose high-level programming languages. It's just not something I would consider appropriate for the kind of language I am proposing, though I still ponder on it.
Though, I think it's rare to expand a pattern match/switch into an if-else tree, and much more common to expand an if-else into a 2-way pattern match/switch.
If you're really keen on such a language, you could fairly easily implement such a language as a pre-commit hook source code re-formatter so that all of the source in your repository is in your favorite language subset.
Therefore, coming from a computer science background I don't like 'unless'.
(For context: I dropped out of comp sci and took a job as a web dev ~18 years ago. Never looked back. But have ended up learning more about copywriting and marketing than computer science along the way.)
I always have to stop at an unless because the double-negative is really hard to evaluate in the mind IMHO.
IMHO unless leads to unnecessary nesting. In your example, it reads like _most_ people are ruby dev. I try to keep the most-often excecuted flow as flat as possible (happy path) and just try to nest for additional/special cases. Unless just tries to do... different.
“Unless” is a conjunction, and its presence creates a double negative with the end of the sentence making the sentence extra clunky (“unless you’re a Ruby dev, you shouldn’t read this article.”)
A few iterations later, we get to the correct syntax, “read this article if you’re a Ruby dev.”
The if !ruby_dev (read as "if not ruby_dev") is so much easier.
The one place I’ll often use unless is things like:
I think it might have something to do with:1. How abundantly clear it is that the condition is a Boolean; and
2. The “false” condition indicating a “no work to do” situation.
I think I only use them for postfix return, break, next, and raise.
The `unless` is idiomatic to the Ruby way of thinking.
if (true) and if not(true) is simple and elegant, and doesn't require any person on my team to stop their flow to puzzle out what the code is supposed to be doing at that point.
You want a well-justified, inclusive, and consistent yet adaptable style when collaborating with people. It would be selfish to gatekeep a policy without regard for those principles.
Also note that unless itself contains another negative ( < medieval onlesse)
It's just easy to see if more than one conditions are evaluated:
if (!ruby_dev && cpp_dev)
vs
unless (ruby_dev && !cpp_dev)
Let me put it this way: Are there _any_ programming paradigms that don't get poorly used? We need to learn how to use our tools well, not reduce them to banality.
Everyone's lazy or overwhelmed at some point, and it made mistakes too easy to make (the problem is that it overtightens the lug nuts because the ease of use removes the proper physical feedback).
In situations where you don't have the bandwidth to perfectly educate everyone and enforce rules, sometimes it's easier to limit the toolset. A tire iron can be misused too, but it's a little harder.
The whole point of Ruby - the only reason it really exists - is that it should be fun and easy and not require you to spend too much time stressing over rules. If you read a piece of Ruby and don't like it, change it. It's not Python - there is more than one way. Use the way that makes sense in the context you're using it.
If you can't trust yourself or your team to do that wisely in a project, consider changing languages, because guess what? The language isn't going to change because you don't like that thing.
Were I reading through real-world code that did things like that:
"OK, then we do this, and then we do that, and then-- Oh wait! Backtrack! We didn't do that thing at all! ... Now where were we, on our actual bug, before some very special person's syntactic speed bumps?"
It's an opportunity to get better at something versus banning it from usage because we aren't used to it.
Growing is, for me, almost always the right choice.
Regarding `unless`, that's a different matter. I was actually the person who proposed adding an `unless` syntax to Racket, and later regretted it. I was bikeshedding, before I knew something more useful to do.
This isn't about learning new things to add to our mental toolbox. This is about our difficulty to introspect on our own thought processes and effectiveness, and about bikeshedding.
Software engineering competence is hard, or we wouldn't have all the huge expenditures, slipped project schedules, and rampant security vulnerabilities. Redundant syntax forms that objectively makes it harder to read (see the lookahead and parser theory), solely because someone imagined it was sometimes easier to read this way (see dying languages Perl and Ruby) is just wasting our time, when we could be tackling the real problems.
(Though us pulling theories about programming and process out of our posteriors, to defend to the death, is arguably half our problem in industry right now.)
I would go so far as to suggest jumping into Rubocop "cold turkey", meaning all rules on, is not very helpful on an existing codebase. The way my team approached Rubocop on a particular large legacy codebase was to start with a few hand picked rules that were non-controversially good, and discuss new rules one at a time as we gradually fixed the existing issues.
https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Unle...
https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Unle...
What may start as a simple single condition, may not remain that way a year later.
Since there's always the possibility of a certain conditional becoming more complicated, it makes sense to opt for the equivalent solution that makes adding those additional conditions easier.
The alternative is to change the keyword when you add those additional conditions, but in most workplaces it's very possible that someone with less rigor than you might come in and add those new conditions and not make the change.
And then if you want to add a new condition you need to parse and understand the more complicated new conditional first, before you can change it.
This adds a lot of maintainability risk for what appears to be, in the best case, a very minor benefit.
It's far simpler to ban use of unless.
I wholeheartedly disagree and believe we should instead grow the developers to understand these different approaches as opposed to labeling half of the language "bad practice".
As I said in another comment. Ruby was built to have multiple ways of doing the same tasks and criticizing it for this is... pointless.
Yes people can create monstrosities with all of these variations, but that's true with any powerful tool. If you dislike Ruby for being Ruby, pick another language.
But there’s such a thing as too much flexibility, expressiveness and flexibility often go hand in hand as flexible language lets you make things as expressive as you want… but things can be expressive without the same level of flexibility if they are well designed.
I find Rust strikes a good balance for low level language work, it feels more expressive than C because of higher level language features but it’s not necessarily as flexible as C with things like the borrow checker nagging you to be safe unless you turn it off.
Lisp… too flexible, too expressive. Lisp code reminds me of the phrase “that depends on what the definition of is, is”.
Scheme and scheme likes including weird step cousins like JavaScript share the unfortunate result of this and your drowning in custom DSLs and no one quite codes the same way unless you have rigorous tooling to enforce a team style.
Ruby falls foul of this for me too. It’s too flexible, it’s very expressive and I enjoyed reading the tutorials and learning the basics. But the moment I discovered real code I was immediately recoiling in horror …. It was a disaster… a spaghetti mess of overrides redefining and meta-programming in general. It made it impossible for me to ever trust the environment I coded it since I had to constantly inspect everything to make sure someone hadn’t done something crazy like enhanced the “+” sign to transform numbers to strings for avoiding something like a sql injection risk in a specific context and whoopsie, leaked the behaviour globally so now any time you added integers you got concatenated strings… but only after the library was dynamically loaded on first query … maddening stuff…
Stuff like this is why ruby is too flexible.
I understand business idea of having monkeys producing code for cheap but I think this approach is misguided.
Exactly the reasons I use C++. Well, after crazy performance, efficiency and single executable deployment.
> As I said in another comment. Ruby was built to have multiple ways of doing the same tasks and criticizing it for this is... pointless.
Agreed 100% with this take. If I only wanted 1 way to accomplish something no matter how inelegant it might be in that context, I would use Python. I choose Ruby specifically because of how expressive it is. It makes it a bit tougher when working in a team with 2 or more opinionated devs, ie. "should we use more functional or more OO approaches to solve a problem" but this is a culture and communication issue, not a language problem. Having a good rubocop setup and staying within the confines of your agreed upon ruleset is a good start.
For example you can use rubocop to enforce dissallowing `unless !condition`, then it's just not an issue anymore - these kinds of issues dissapear before code even makes it to review.
Not exactly the same, but over the years I've heard people argue against having super customized shell configurations (e.g. completions, prompts, highlighting) because they won't be available if you have to use a different environment (e.g. sshing into a temporary cloud server to debug something failing in CI). I don't pretend that other people will value tradeoffs the same as me, but it's a mindset I can't really imagine ever having. I'd rather be happy most of the time even if I know I'm going to be unhappy for short periods occasionally in the future, and I don't really think the slight efficiency gain in the uncommon case due to being used to not having nice features is going to outweigh the larger efficiency gain for the much more common case.
At the risk of straying entirely off-topic, I've seen this in non-professional contexts at times as well; I recently had a friend in an online game mention that he doesn't like to utilize a convenience feature that happens for a couple weeks each year as part of a special even because he would miss it too much the rest of the time. While I don't think the tradeoff is quite as obvious to me for this sort of thing, I feel like occasionally having a fun temporary addition is worth it just for the change of pace, and I'm generally able to adapt to the loss of a minor convenience relatively quickly after losing it. It seems sort of like a question of "maximizing peak happiness" versus "minimizing peak unhappiness" or even "maximizing average happiness"; I like having something to get excited about every now and then even if it leads to feeling blase about things for a bit later because I get bored if things stay the same for too long.
I switched from QWERTY to Dvorak a long time ago, a few years after learning to touch type. Does it make me more efficient on my own computer? Probably slightly -- Dvorak really is a well-designed keyboard layout, but it's impossible to know whether my WPM is any higher than it would've been on QWERTY. However, I make way more mistakes and type way more slowly whenever I sit down at a QWERTY keyboard. I had to re-learn how to touchtype QWERTY after switching to Dvorak, and my skill never got back to the same level. It also leads to extra inconvenience every time I lend my computer to someone else, install a new OS, etc.
I think this means my average typing speed (weighted average of the time spent at Dvorak keyboards + QWERTY keyboards) is probably flat or possibly lower than if I had just stuck with QWERTY. When combined with all the effort I spent learning Dvorak, re-learning QWERTY, and making many mistakes in the early years, I think my lifetime productivity is probably even lower. I don't recommend that people switch, even if I think Dvorak really is a better layout.
> there’s this bizarre quirk of human psychology where developers retain the unless against all odds
I have refactored a number of unwieldy `unless` statements written by colleagues so maybe there’s something to that.
That said, I only use it in 2 cases:
* as a trailing condition (do_something unless this), mainly for early returns * as the only arm of a multi-line block (unless this ... end, no "else" blocks - Rubocop would yell at me anyway)
And then only if the condition is either a simple value, or a combination of simple values (this && that, this || that).
That's it. Never had a problem with double negatives or accidentally inverting the logic.
Of course one can avoid it at all but of course one cannot avoid to spend time on it when reading somebody's else code.
It's the exact opposite of pythons "There should be one– and preferably only one –obvious way to do it" - they intentionally create solutions that have zero practical benefit - it's just fuels arguments based on preferences and introduces mental overhead due to inconsistency.
And Perl literally has the opposite design principle, TIMTOWTDI or "there is more than one way to do it".
I'm not arguing here -- I prefer the "one obvious way" principle.
But you can design a beautiful programming language without regard for the long-term learnings of software engineering.
I always liked Perl's "unless", and I always made sure to not abuse it with double negatives or other contorted conditions that are, in themselves, reasonable. I also promised myself I wouldn't write very big programs in Perl.
- Matz, c.a 2003
it's literally just `!` equivalent. Honestly I haven't seen much code using unless in wild. Especially that it is literally shorter to just !
Just an example: "if x is not None:" is syntactic sugar for "if not x is None:".
String formatting: there are f-strings, % replacement, .format, probably more methods.
And that's fine, languages evolve over time, add better ways to do things, and don't deprecate the old way.
It's the hypocrisy of flaunting that motto while the language is so full of the exact opposite that always annoys me.
However, a lot of developers love very strict style guidelines. I've never understood why, but it's a discussion I get into very very often.
In a shared codebase, I think there should be as few (equally effective) ways to express an idea as possible. (Obviously there can be more- and less-efficient ways to write a function; I'm referring only to style.) The more arbitrary choices people have, the more time is wasted on choosing one.
If you're coding alone, that's fine - you just pick what you like, and spend as long as you like making that decision. But in a shared codebase, developers writing in different styles is a net negative on quality & readability. Spending time debating which style to prefer is a worthwhile, but unnecessary time sink. Automatically enforcing a pre-defined style is efficient and effective - that's why Prettier exists, is widely used, and has few configuration options.
I highly disagree! In my experience, forcing arbitrary style leads to so much more time wasted as people debate exactly which styles to enforce.
> But in a shared codebase, developers writing in different styles is a net negative on quality & readability. Spending time debating which style to prefer is a worthwhile, but unnecessary time sink
I disagree with this too. I have never found this type of style to be something that actually impacts readability and quality. If you using `if !` and I using `unless` is the problem with the codebase, that's not so bad.
I have to say, this is why I'm a huge fan of Python's black. It lets me write however I want, while you get to read my code in a consistent style.
> forcing arbitrary style leads to so much more time wasted as people debate exactly which styles to enforce
If this is happening often, I would unambiguously call that a problem, though. It should only happen once (and then, when enough has changed in the frameworks, maybe once again). This is exactly the philosophy Prettier takes: it is purposely difficult to change. It works really well as it is, and keeping it constantly optimized for community preference would be an anti-pattern.
> I disagree with this too. I have never found this type of style to be something that actually impacts readability and quality. If you using `if !` and I using `unless` is the problem with the codebase, that's not so bad.
I more or less actually agree with you on this. Small stylistic differences are generally negligible. But variations add up, and some are more egregious than others. I consider this more of a guiding philosophy than a rule; `if!` vs `unless` on its own is not a real problem.
I'll never understand these sorts of articles because they criticize the subject for not being what they explicitly aren't.
"I hate spoons because they can't cut like knives"
Really curious to see the one and only one obvious way these are handled.
> It indicates you don't understand Ruby if you find yourself using an "unless" in a complex boolean operation. It's meant for simple cases like an inline return statement
is not exactly very readable and this isn't glancable either. Just random snippets from Rails code. You can see how author wanted some bonus points and used unless, if, and ! too. Sure it isn't hard to figure out but it makes it needlesly obtuseYep that's why I hate ruby - worked on one mature codebase for a year and after seeing various such gems used across the project - from >10 devs - I'm confident I will never touch the language again.
In any case, the Ruby community already has good guidelines on the "Unless" usage, there are few scenarios where they are useful but it's not like you find them everywhere in a codebase.
For example, we don't use "Unless" with "Else", or use Unless with negation (like the article), or use Unless in nested If statement, etc. Rubocop will catch many of these and warn you.
My point is that experienced engineers will use the language as it was intended to and not abuse its features.
I'm not arguing other languages can't produce bad code, just that ruby is particularly suited for it especially as number of developers working on code increases. I've seen people propose a linter to enforce consistency - but at that point I might as well chose a language with better design choices - plenty of alternatives these days.
You're seriously proposing that adding a linter has the same organizational costs as changing languages entirely. Meanwhile, back in the real world...
Ruby has major advantages over many other languages and a linter is basic tooling you should have in every development environment.
Regardless, all of the languages above except C and maybe Object Pascal can still have control stop in the middle of an expression, since an expression can throw an Exception (indirectly). Returning is not significantly different from that.
Er, what?
You understand almost everything in Rust is an expression right?
That return is an expression, obviously we mostly care about the expression's side effect which is a change of control flow to leave the function with some sort of integer 5 as the return value (the function signature tells Rust which kind of integer this 5 is) - but the expression "return 5" itself does have a type, it's ! aka Never, an Empty Type because no values of this type can exist - because the side effect will change the control flow before we need a value.Rust's type inference engine is fine with this because under type arithmetic all the values fit in a single type, the type of "X" - &'static str - there are no values on the left to disrupt that.
E.g. "42 == (return true)" is a syntax error while "42 == if false; true; end" is syntactically valid.
You can return in the expression in the comment above because the return is at statement level - nothing above it in the grammar requires a value (but obviously allows it).
Off the top of my head I can't remember which other keywords fall in that category. Obviously "end", "then", "alias" and there'll be a few more, but for most keywords in Ruby you're right they can be treated as expressions.
- beautiful is better than ugly => tell that to numpy or pandas
- readability counts => (¬з¬)
- if the implementation is hard to explain, it's a bad idea => then the World is full of very bad ideas
I know boolean logic pretty well, but `unless !something` still trips me up to this day.
Same in Spanish!
I think you're making a very good point here – understanding "unless" (quickly, i.e. without having to think about it) very much depends on one's understanding of the English language and/or one's mother tongue. Sure, one can probably get used to it (like one gets used to what "if/else" means etc.), but it definitely increases the mental effort needed to read & understand code.
If and unless are English language keywords besides being Ruby keywords; and in Spanish, the word for "if" and the word for "yes" only differ by an accent mark.
"No! (Wrong!) There is no ..."
Bringing it back down to 1 level of negation, for it to make logic sense again.
E.g. `I can't get no satisfaction` is structurally equivalent to French `ne ... pas`, i.e the second `no` is a reaffirmation, not a negation.
On the other hand `read this unless you're not a developer` is a logical double negation and thus equivalent to `read this if you're a developer`. In practice of course there are usually implied subtleties that make the two not entirely equivalent (the same way synonyms are conceptually interchangeable but may carry different subtext).
EDIT: I can't actually think of any true "double negative" in English that isn't indirect (e.g. `indirect` being synonymous with `not direct` thus `not indirect` being synonymous with `not not direct` and `not not` cancelling itself out). The only direct forms I can think of behave like `not ... no` in my first example, i.e. re-affirmations of the negative rather than double negations.
I think most of the complaints about "double negatives" (where the Rolling Stones line is usually cited as an example) are stylistic preferences or intentional misunderstandings based on arbitrary prescriptions (which are usually based in other languages like Latin that are perceived as "purer" or "more sophisticated").
"Ain't nobody got time for that" is clear, likewise "I didn't go nowhere" and "He ain't take nothing from nobody" and when something is not clear ("That ain't nothing" could mean it is, or it is not, something) context usually suffices.
A: Do you like your hometown?
B: Well, I don't not like my hometown
In boolean logic, not false is true, but in English there's often a middle ground. See also https://en.wikipedia.org/wiki/Law_of_excluded_middle
I'd argue that in "I don't not like my hometown" not-liking acts almost as a compound verb, similar to "disliking" (which is just using a Latin prefix to say "not"). Resolving the double negative results in information loss because it omits the subtext (which in this case is the important part of the answer).
In other words, saying "I don't not like my hometown" makes sense because "I don't like my hometown" implies negative emotions (disliking) rather than an absence of positive emotions (liking). The difference could also be conveyed in emphasis ("I don't like my hometown") but this is more subtle and easier to misunderstand.
And I'll take it one step further: I see a multi-line branch as a code smell in and of itself. If something in a branch takes multiple statements, I am of the opinion that the body of that branch should probably broken out into a method.
So if we're going off the article title, my code might look something like
Since unless has a not built into it, it has a lot of potential to confuse people. In my experience, guard clauses are the only place where they make sense.
In this sense, you know that the entirety of the function is an expected (positive) case.return unless token.present? return unless user.valid? return unless foo = get_foo(user)
Its extremely readable and easy to grok imo.
I always insist on not using 'unless' if it's not clearly readable as an english phrase or if there's an 'else' as well.
A similar pattern I follow with 'if !'. If there's an 'else' condition always put the positive check first and the negative one in the else, rather than the other way around.
Footguns are equally possible using complex 'if !' statements.
1. It is a negative, and that is a great thing when there are boolean conditions. Yes, you can wrap the whole thing in brackets, but when doing a visual scan quickly over code, they're easier to miss than the giant `unless` token which guarantees that you won't have an early closing bracket. The more the number of terms go up, the more I have to be fastidious with watching where brackets begin and end.
2. It hints to the expected flow of things. Isn't the first more readable to you?
Or I'll put it another way. If you do a search of your own hacker news comments on BigQuery, will you never find the english word "unless" outside of a Ruby discussion there? You could say "if not" why bother using an extra word? Or what about "not true" do you ever say that when you could just say "false" like Dwight from The Office?Basically my argument boils down to this:
Bears. Beats. Battlestar Galactica.
I disliked it as well in CoffeeScript. The use of else blocks is especially annoying, but even otherwise I don't like it. Some might say you shouldn't use it with an else block, but this is not realistic if you work in a team.
- Many remarks concern the difficulty of understanding "unless" for those with a first language other than English. It may be interesting to note that Ruby was created in Japan, and that "unless" has been in the language since the very first release. [1]
- Matz has a very interesting and famous quote about the principle of least surprise: "it means the principle of least surprise after you learn Ruby very well." [2]
- Computers don't care how programs are structured. Businesses don't care how systems are architected. The canvas does not care how paint is applied. Software engineering is an art. [3]
---
1. You can verify this yourself - check `parse.y`: https://web.archive.org/web/20071109044522/http://eigenclass...
2. The rest of the quote is also wonderful: https://www.artima.com/articles/the-philosophy-of-ruby#part4
3. The article that contains this line has fundamentally altered how I view our profession: https://www.neversaw.us/2022/01/30/the-canvas-cares-not/
Yes, sometimes you have to refactor into a traditional if. Sometimes you make the conditional its own method (which you’d end up doing anyway, assuming it didn’t stop at two or three conditions.) These are light tasks as the project grows.
Starting a line with unless, on the other hand, does not work for me. It is also awkward in short English sentences. And long English sentences, where beginning with unless is more appropriate, don’t have analogies in single-line ruby statements.
That's a problem for those who learn it as a second language and have to translate "unless" to "if not" every single time.
Of course it is logically equivalent to `if not`, but it is pragmatically not conveying the same information at human interpretation level.
However I find some of the examples / justifications unfortunate e.g.
> I find the second option less readable because it suggests that raising the error would be the normal thing to do, when in fact it’s the exceptional thing to do.
It’s not tho. The normal thing to do is to reject access, being an admin is exceptional. A restricted endpoint should absolutely assume the user is not authorised.
Not unique and not the best, but popular and usable enough to be fascinating for anyone who's given more than passing thought to how difficult it is to communicate in any one realm separately (let alone across realms).
For example, I had a meeting with POs recently where it took an hour to communicate a concept in English and distill a logic diagram from it. I'm not placing blame on English (although some would [1]), POs, or myself. It's just common experience that communication is difficult.
Personally I always enjoy flexibility and expressiveness when writing (English or code), usually when reading (English or code), and sometimes when debugging (English or code). So I like Ruby pretty well. YMMV.
[1] https://news.ycombinator.com/item?id=33513666 & https://news.ycombinator.com/item?id=22689959
(when CONDITION BODY)
(unless CONDITION BODY)
The value of the statement is BODY or NIL if it wasn't executed.
I can't remember a time when it wasn't clear (though you can always build usage that are unclear).
Just because of that they are far superior to if/else/unless, unless ;-) you're using the ternaries to execute statements with side effects instead of just returning a value.
> As a general rule I think that if a language has some feature for which there is already a commonly understood syntax across other languages, it should just use that syntax. If you’re introducing a complete paradigm shift, then that’s fine, but unless is not that: it’s just a different way to write if ! and people jumping back and forth between ruby and, say, javascript, now have one extra idiosyncracy to keep in mind.
Most statically-typed languages don't let you evaluate 0 as a boolean.
IMO, 0 is a value, and values should be truthy. 0 being falsy is only a wart from C.
I don't know off the top of my head, but I would assume that yes, zero is truthy in Erlang as well, since Elixir is fully compatible with it.
Although I like 'unless' in Ruby, Perl, CommonLisp (sometimes a condition is just naturally the other way of how 'if' wants it), I acknowledge that people get emotional and really hate it. Maybe a better alternative would be 'ifnot' to avoid the ! operator and the parentheses.
Use the tools.
I had actually decided to write them as if statements because that way I didn't have to make one particular logical check (I can't really remember what the logic was, just that it had to do with language and Swedish language legal documents did not have a particular rule that Danish ones did.
So a senior Ruby dev who admittedly was a lot better than me in a lot of things but did have the habit of making incredibly boneheaded bugs sometimes, went through and rewrote all my if statements as unless statements - inadvertently reversing the logic.
A week later bug comes up I get blamed because it was the thing I worked on I was embarrassed, and I went through the code fixing but then I thought - wait I wouldn't have written this as an unless because I need to do one extra statement that way! After digging through I caught our senior dev, the very guy blaming me for causing bugs.
Ah the revenges of youth are very sweet.
Do I think Ruby NEEDS unless? No. Does this keep me awake at night? No lol
Honestly, I find negative checks like `if !something` ugly, I would much rather check if the result is true than !true. The same with unless, I would prefer to check unless false than unless not false or unless !false
Basically, do_something unless A
Then it's simple now to manipulate the inside of A, as you only take care of the positive ! That's beautiful and simple design.
Example is you want to validate something.
raise Error unless someValidCondition.
Now decompose someValidCondition by just using positive connectives, simple right ?
X = 5 unless invalid_token
Much better than
X = 5 if !invalid_token
Here the humans inability to easily process double negatives, is now an argument for using ‘unless’ in the right circumstances.
But that's actually ideal in this context, a really low precedence operator is exactly what you want because you can swap `unless` for `if not` without worring about extra parentheses:
send_email if not user_suspended? || user_opt_out?
I generally avoid `not`, `and`, `or` keywords.
[0] https://www.google.ru/books/edition/Foundations_of_Mathemati...
Things like this sound like: "I have this characteristic, therefore everyone has this characteristic."
Some of us ain't got no problem with double negatives, and often find that "unless" tightens up code nicely, especially for single negatives.
A long time ago, a friend code reviewed and asked me to change to the most common condition first, as advocated in the Code Complete book (which I hadn't read at the time).
I still think it reads better if/else as true/false, but I am also big on having standards and a coding style, even if I disagree with them.
I mean, unless there's a lack of coding standard I will follow it.
`return if not valid?` or `return if invalid?`
Both make sense in my brain, whereas
`return unless valid?`
Feels like I need to make another connection to understand it
That said, I think the author is overselling the need to not use such features. Despite my aversion to using such features, I have no problem reading them.
(the headline however, is an exceedingly bad example)
I find inheriting code riddled with witty logic puzzles distasteful, so prefer my predecessor to have written Python, which constrained them from crafting too many.
Some people want a project to be a series of cryptic crosswords. For them perl/ruby/C.
When I write perl/ruby/C, I restrain myself from filling it with cool puzzles, but I usually don't get to inherit code from myself.
You can address it with code reviews/standards/linters and get the best of both worlds.
It means "skip if zero".
The double negative always trips me up.
I had to write "don't skip if not zero" next to it the first dozen or so times.
The spec says that [t]he functions delete-if-not and remove-if-not are deprecated.
But all that is wrong is their double negative name. remove-if-not is precisely the same thing as keep-if, which is too useful to deprecate. Numerous languages have a function like this, sometimes called filter or similar.
> Read this post ‘unless’ you’re not a Ruby developer
But:
> Read this post if you’re a Ruby developer
Surely?
Seriously though, the main way Ruby went wrong was an obsession with this entirely superficial kind of expressiveness and simplicity. Rubyists will lard their code with all sorts of "convenient" and "easy" features, to save a few keystrokes here and there, at the expense of bloating their APIs and hiding weird, hard-to-reason about magic.
IF some-expression
ELSE Do-something
do not do <statements> unless not <expression>
of some fun programming language whose name I forgot.
You don't understand Ruby if you think there is something wrong with trying to have more than one option to do things, imperfect shortcuts and more human-readable code.
Unless works really well when there is one named boolean variable after it and it's named correctly or if the condition is simple to understand.
It also works well when used inline and without an else statement. For other cases "if" is better-suited. But then again "unless" is another option in your tool chain that makes for a more elegant programming language if you're not a stickler and not constantly finding yourself pining for a platonic language.
It'd be easier to miss the "!" character in the case of "if !".It also makes code read better in English.
Obviously if your specific language doesn't make use of it, or makes use of it in a different way to ruby (e.g. is your natural language treating the second negative as a negation of the negative, or an intensifier of it?) then ruby's grammar will seem unnatural. But that's going to be true for anyone who's trying to map their natural language onto a programming language whose grammar is different to theirs.
I "grew up" in my career as a rails dev myself, but I favor things that are immediately clear to the broadest amount of people possible these days. And if you truly miss these constructs, in any language where you have metaprogramming, which is most these days amongst the broadly used ones, it should be trivially to implement them, should you insist on continuing to use them.
I use Elixir for my "fun" language these days, and they provide unless/2 as a macro, (if/2 is also a macro), but I haven't found myself reaching to use it once.
If I've neglected to address your specific criticism I'm happy to do so here