[HN Gopher] Read this post 'unless' you're not a Ruby developer
___________________________________________________________________
Read this post 'unless' you're not a Ruby developer
Author : genericlemon24
Score : 213 points
Date : 2022-12-13 07:41 UTC (15 hours ago)
(HTM) web link (jesseduffield.com)
(TXT) w3m dump (jesseduffield.com)
| PaulHoule wrote:
| I liked "unless" in Perl and also the X if Y
| X unless Y
|
| syntax. I want to see some language that brings back the "noise
| words" from COBOL for that matter.
| athenot wrote:
| For all of Perl's permissiveness, this is one situation that is
| explicitely dissallowed: unless condition
| # do A else # do B end
| lucidone wrote:
| 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.
| ilyt wrote:
| and why def my_method(required_thing)
| raise 'required_thing is required' if !required_thing.present?
|
| is a problem ?
| lucidone wrote:
| 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".
| otikik wrote:
| Do not use unless Unless it's a one-liner
| rwoerz wrote:
| Reminds me of the
|
| do not do <statements> unless not <expression>
|
| of some fun programming language whose name I forgot.
| [deleted]
| FpUser wrote:
| When reading code ! in condition can be overlooked relatively
| easily so I do not really see anything wrong with "unless".
| hk1337 wrote:
| 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
| snshn wrote:
| Clickbaity. Very clickbaity.
| inerte wrote:
| 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.
| arunix wrote:
| This is a useful feature to have when writing one liners e.g.
| % cat words all these worlds are
| yours
|
| Which I believe is one of the reasons Perl allows it:
| % perl -ne 'print unless /^a/' words these worlds
| yours
|
| And Ruby does too: % ruby -ne 'print unless
| /^a/' words these worlds yours
| azlev wrote:
| Some people like, some people hate, that's why we have multiple
| languages to choose.
| 0x457 wrote:
| 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.
| sshine wrote:
| I'm currently writing assembler for a virtual machine that has a
| "skiz" instruction.
|
| 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.
| uticus wrote:
| 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.
|
| [1] https://news.ycombinator.com/item?id=33513666 &
| https://news.ycombinator.com/item?id=22689959
| zelphirkalt wrote:
| Ruby is not the only language with "unless", actually. For
| example it exists in GNU Guile as well (https://www.gnu.org/softw
| are/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.
| Lapsa wrote:
| and why does Rubocop's Ruby Style Guide matter?
| Karunamon wrote:
| 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.
| ndsipa_pomu wrote:
| 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.
| thunderbong wrote:
| 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.
| actionfromafar wrote:
| I had to read the title five times to decide if I was supposed to
| read it. I'm sold.
| mypastself wrote:
| Are you saying you _don't_ want to have to apply De Morgan 's
| Theorem any time you read a headline?
| eyelidlessness wrote:
| 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
| eyelidlessness wrote:
| 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.
| trfzx wrote:
| I think the author would probably be fine with an if-not.
| It doesn't hide the double negation like unless.
| [deleted]
| layer8 wrote:
| So you'd be in favor of dropping "unless" from the English
| language because it was misused in that title? :)
| revskill wrote:
| You need to use it when you want to be negative of ALL the thing
| after unless.
|
| 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 ?
| jpmattia wrote:
| > _The human brain, impressive as it is, grinds to a halt when
| parsing with double negatives._
|
| 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.
| celeritascelery wrote:
| 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.
| stormdennis wrote:
| Unless would drive me insane. I do use IF NOT but when reading
| code my brain understands this format most clearly:
|
| IF some-expression
|
| ELSE Do-something
| shortcake27 wrote:
| `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.
| Alifatisk wrote:
| This, I've mostly used unless with guard clauses
| codegangsta wrote:
| 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
| al2o3cr wrote:
| TLDR: "I don't understand De Morgan's laws and so it's the
| languages's fault" :P
| jbaber wrote:
| 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.
| davedx wrote:
| 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?
| phplovesong wrote:
| 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.
| stefano_c wrote:
| 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.
| pmontra wrote:
| 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.
| masklinn wrote:
| 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.
| gjadi wrote:
| In Common Lisp, there is `unless' and `when' but they don't allow
| `else' branch.
|
| (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).
| tsimionescu wrote:
| I think they mainly exist because `if' otherwise requires a
| `progn' if you want more than one expression in the true
| branch.
| tmtvl wrote:
| And using `cond' for 1 clause is a bit silly.
| (cond ((massivep building) (print-mass-warning
| building) (install-antigrav-module building)))
| corytheboyd wrote:
| 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
| masklinn wrote:
| 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.
| dkdbejwi383 wrote:
| 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)
| e12e wrote:
| That example makes more sense as: send_email
| unless user.suspended?
|
| Here we see that we normally send email - except for the
| exceptional case of the user being suspended.
| PaulRobinson wrote:
| 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.
| neilv wrote:
| 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?"
| Draiken wrote:
| 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.
| neilv wrote:
| 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.)
| torton wrote:
| 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.
| ufmace wrote:
| 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`.
| jbverschoor wrote:
| I almost never write unless, unless it makes absolute sense in
| English, and it only has one condition
| eric-hu wrote:
| never_write_unless unless makes_sense_in_english &&
| has_only_one_condition
| sod wrote:
| 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.
| sph wrote:
| 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.
| hnbad wrote:
| 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").
| tialaramex wrote:
| 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.
| sixhobbits wrote:
| > any true "double negative" in English that isn't indirect
|
| 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
| sshine wrote:
| Ain't nobody got time for that!
| jjgreen wrote:
| yeah yeah
| soheil wrote:
| Funny how human languages converge.
| codethief wrote:
| > 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.
| yebyen wrote:
| 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.
| zelphirkalt wrote:
| In Spanish I usually translated double negation like this:
|
| "No! (Wrong!) There is no ..."
|
| Bringing it back down to 1 level of negation, for it to make
| logic sense again.
| jack_riminton wrote:
| I'd never use an 'unless !something', always an 'if something'
| jacobsenscott wrote:
| I don't like!.! Is not a word, but unless is. Unless is great
| unless you use it wrong.
| anm89 wrote:
| 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.
| swyx wrote:
| this title beautifully demonstrates the point. if there were an
| oscars for blogpost titles, this would be a nominee.
| davesque wrote:
| 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.
| vidarh wrote:
| 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)
| 3pt14159 wrote:
| 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?
|
| Basically my argument boils down to this:
|
| Bears. Beats. Battlestar Galactica.
| evolve2k wrote:
| Assume all references to valid_token were to an opposite method
| named 'invalid_token' and suddenly the 'unless' will make much
| more sense.
|
| 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.
| rodgerd wrote:
| 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.
| hbrn wrote:
| I've seen quadruple negatives in Python: if not
| no_unavailable_items: ... else: ...
|
| unless on it's own is fine, but humans will misuse it if you're
| not careful.
|
| You can address it with code reviews/standards/linters and get
| the best of both worlds.
| schneems wrote:
| 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.
| jmuguy wrote:
| We use it exclusively for guard statements at the beginning of a
| function, and we keep it to a single statement per line
|
| return unless token.present? return unless user.valid? return
| unless foo = get_foo(user)
|
| Its extremely readable and easy to grok imo.
| [deleted]
| beeforpork wrote:
| 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.
| pmarreck wrote:
| Elixir has the same "unless" statement but I hardly see it used
| in practice, and frankly I've never missed it, probably due to
| the reasons cited
| gmiller123456 wrote:
| 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.
| lamontcg wrote:
| 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).
|
| Use the tools.
| mrtweetyhack wrote:
| shortcake27 wrote:
| 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.
| tebbers wrote:
| Exactly my first thought too.
| doodpants wrote:
| 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.
| airstrike wrote:
| SURGEON GENERAL'S WARNING: reading this sentence before
| consuming caffeine may cause significant brain damage
| scambier wrote:
| I'm not sure that making this sentence as obtuse as possible
| is a great idea to convey your point.
| lsaferite wrote:
| Making it as obtuse as possible was very likely _the_
| point.
| thedanbob wrote:
| To be fair, he makes the point that
|
| > 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.
| roboben wrote:
| 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!
| aqme28 wrote:
| 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.
| JeremyNT wrote:
| Yes! And rubocop can encourage the use of 'unless' in only
| these simple situations where it does enhance legibility.
|
| https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Unle.
| ..
|
| https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Unle.
| ..
| saghm wrote:
| > "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.
| meatmanek wrote:
| 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.
| Draiken wrote:
| 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.
| rubyist5eva wrote:
| > 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.
| FpUser wrote:
| >"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.
| fl_ciq wrote:
| I like C++ because I find angle brackets to be harmonious
| to the eye.
| techdragon wrote:
| 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...
|
| Stuff like this is why ruby is too flexible.
| FpUser wrote:
| 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.
| asdajksah2123 wrote:
| 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.
| shortcake27 wrote:
| 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.
| draw_down wrote:
| WillPostForFood wrote:
| 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.
| quest88 wrote:
| 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.
|
| It's far simpler to ban use of unless.
| WillPostForFood wrote:
| It is neither weird, nor complex. Use unless in cases
| where the if has a single, negative condition.
| locallost wrote:
| 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.
| soheil wrote:
| "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 !".
|
| It also makes code read better in English.
| ilyt wrote:
| I found that if not opening new scope was way more annoying than
| _option_ to use unless that nearly nobody picks. I.e
| if cond a = 1 end
|
| leaks a to outside and a will be nil if condition does not happen
| rco8786 wrote:
| Love Ruby. Hate unless.
| DogLover_ wrote:
| Kinda similar, you oftentimes don't need to use an `else`
| statement. It is way overused and leads to code with too much
| indentation.
| dimitrios1 wrote:
| 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.
| 1123581321 wrote:
| 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.
| brabarossa wrote:
| >It reads like natural English
|
| That's a problem for those who learn it as a second language
| and have to translate "unless" to "if not" every single time.
| 1123581321 wrote:
| 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."
| clolege wrote:
| 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.
| weatherlite wrote:
| I agree guard classes are great with unless...other places not
| so much
| gexla wrote:
| 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.
| kazinator wrote:
| 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.
| weatherlight wrote:
| 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."
| thomascgalvin wrote:
| 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
| aidenn0 wrote:
| 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.
| ricardobeat wrote:
| 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: valid_token =
| token.valid? && !expired return 'invalid' unless
| valid_token
|
| 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).
| bryanrasmussen wrote:
| 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.
|
| Ah the revenges of youth are very sweet.
| OliverGilan wrote:
| 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
| fl_ciq wrote:
| 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.
| yanis_t wrote:
| gsinclair wrote:
| Only false and nil are falsey, and the language shines for it.
| There is nothing weird about zero being a truthy value.
| fl_ciq wrote:
| In what other languages does 0 evaluate to true?
| nanny wrote:
| Lua, Elixir, Common Lisp, Scheme, Racket, Clojure.
|
| 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.
| fl_ciq wrote:
| 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.
| jacobsenscott wrote:
| Yes, this is one of ruby's best features.
| moonchrome wrote:
| 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.
| nonrandomstring wrote:
| In Perl I once saw someone write; unless
| predicate do this else unless impossible_thing
| do the impossible
|
| What it did at runtime I have no idea, but it broke my brain
| for the rest of the week.
| ilyt wrote:
| if !cond1 do this elsif !cond2
| do that
|
| ?
|
| it's literally just `!` equivalent. Honestly I haven't seen
| much code using unless in wild. Especially that it is
| literally shorter to just !
| sshine wrote:
| 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.
| gpvos wrote:
| I only know `unless` from Perl, and it can make your code
| clearer if used sparingly. For example it allows you to
| express preconditions positively: die "You
| may only use port numbers 1024 and higher" unless
| $port >= 1024;
| TomSwirly wrote:
| die "Port numbers below 1024 are forbidden" if
| $port < 1024;
|
| is hardly unreadable spaghetti code.
| gpvos wrote:
| 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());
| aspyct wrote:
| Ruby is basically Perl++
| mattm wrote:
| Ruby is Perl 6
| greenpeas wrote:
| ruby is OOPerl
| [deleted]
| lloeki wrote:
| > 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.
|
| - Matz, c.a 2003
| TurboHaskal wrote:
| 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 :)
| nolls wrote:
| drstewart wrote:
| 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.
| aqme28 wrote:
| 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.
| soiler wrote:
| 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.
| vidarh wrote:
| 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.
| Draiken wrote:
| 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"
| fl_ciq wrote:
| Python is a communist apartment block, brutal in design and
| conformity and not very efficient.
| perlgeek wrote:
| Y'know, I've written a lot of python these past years, and
| python is just full of aliases and different ways to do things.
|
| 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.
| peoplefromibiza wrote:
| > It's the exact opposite of pythons "There should be one- and
| preferably only one -obvious way to do it"
| unless python.major_version > 1
|
| other zen of python's rules that did not live up the
| expectations
|
| - beautiful is better than ugly => tell that to numpy or pandas
|
| - readability counts => (!z!)
|
| - if the implementation is hard to explain, it's a bad idea =>
| then the World is full of very bad ideas
| soheil wrote:
| 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 return
| unless User.exists(id=100)
| quietbritishjim wrote:
| 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.
| maybe_pablo wrote:
| Kotlin has this, check out
| https://kotlinlang.org/docs/returns.html
| ckolkey wrote:
| If and unless can be used as post-fix clauses. Also, in
| ruby, -everything- is an expression, so... of course you
| can return from there
| vidarh wrote:
| 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.
| vidarh wrote:
| 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.
| tsimionescu wrote:
| 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.
| [deleted]
| jack_riminton wrote:
| Nah, it's pretty cool once you get used to it
| tialaramex wrote:
| > 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.
| ilyt wrote:
| 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
| moonchrome wrote:
| 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.
| pmontra wrote:
| Those one line returns are particularly handy at the
| beginning of methods, to validate or process arguments and
| return immediately for simple cases.
| hnzix wrote:
| Short circuiting is such a beautiful way of avoiding
| giant nested "if" mountains. I wish it was more widely
| used.
| ilyt wrote:
| 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. condition || return
| soheil wrote:
| 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:
| a=1;b=2;c=3;d=a+b==c?4:5;return d
| moonchrome wrote:
| 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.
| codesnik wrote:
| It doesn't create no scope. Even for variables.
| ezekg wrote:
| Ruby doesn't create a new scope for if/unless.
| multiplegeorges wrote:
| > 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.
| swat535 wrote:
| 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.
| chillfox wrote:
| 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.
| Arubis wrote:
| `unless` is great. Rubocop (used everywhere) would flag and offer
| to autocorrect this title for the double-negation.
| strzibny wrote:
| You are now likely attracting all the Ruby devs here:D
| jjgreen wrote:
| The visual difference between a ! and an l is not that great,
| send_email if !user.suspended?
|
| or send_email if luser.suspended?
|
| The latter could easily be an aggressive dev sending abusive
| emails to users they dislike enough to call lusers, at first
| glance at least ...
| SanjayMehta wrote:
| Brought back memories of alt.sysadmin.recovery.
| quietbritishjim wrote:
| Perhaps a Python style spelt-out `not` for boolean negation
| would have been a better solution for this than `unless` in
| deep retrospect? send_email if not
| user_suspended?
| jjgreen wrote:
| Ruby has "not", but the precedence rules between "not" and
| "!" differ
| quietbritishjim wrote:
| 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?
| greenpeas wrote:
| 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.
|
| I generally avoid `not`, `and`, `or` keywords.
| hnbad wrote:
| Sadly `!` never caught on. But I suppose being visually similar
| to `-` isn't much better.
| Joker_vD wrote:
| 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".
| jjgreen wrote:
| 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
| ...)
| tsimionescu wrote:
| If it's not a shift+<something> key on a popular keyboard
| layout, it's not going to gain widespread adoption in
| programming.
| housecarpenter wrote:
| ! is shift+` on the most common UK keyboard layout, but
| yeah, it would probably need to be popular _in America_.
| forkerenok wrote:
| 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:
| klooney wrote:
| 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.
| asdajksah2123 wrote:
| 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.
| giraffe_lady wrote:
| Those are also expressions in ruby.
| twic wrote:
| 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.
| rukuu001 wrote:
| The actual literal meaning of 'unless' has evaporated from my
| brain trying to parse that title
| shric wrote:
| I'm mildly surprised the article doesn't mention that Perl, one
| of the languages that influenced Ruby, also has unless.
| dgunay wrote:
| 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.
| byroot wrote:
| It's the same in Ruby. It's even mentioned in TFA.
| sshine wrote:
| Those who don't know history are doomed to repeat it. ;-)
| rjsw wrote:
| Common Lisp has unless too, I use it where it makes sense.
| nickelcitymario wrote:
| 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.
| asdajksah2123 wrote:
| The unless is still harder for me to grok.
|
| The if !ruby_dev (read as "if not ruby_dev") is so much easier.
| nickelcitymario wrote:
| 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.
| burke wrote:
| For some reason this one feels right to express with if-not
| to me too.
|
| The one place I'll often use unless is things like:
| return unless valid raise unless h.key?(k)
|
| 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.
| dlkf wrote:
| 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?
| hosh wrote:
| 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.
| antod wrote:
| 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.
| dlkf wrote:
| 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.
| marcosdumay wrote:
| Personally, I don't think "readable by people that don't know
| the language" is a reasonable feature to optimize a language
| around.
|
| And if you go on that direction, almost the everything on the
| language is a larger roadblock than an oddly placed
| conditional.
| afandian wrote:
| I wrote Ruby for years (for fun). I always had to stop and
| think twice about 'unless' and translate it into 'if not'.
| dlkf wrote:
| 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"?
| marcosdumay wrote:
| "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.
| 8note wrote:
| That's a really powerful tool. I can force you to slow down
| an make sure that you the reader focus on one section of code
| I've written?
|
| A statement that forces you to switch out of inaccurate
| skiming mode is insanely useful
| lcnPylGDnU4H9OF wrote:
| 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.
| seydor wrote:
| as a non-native speaker, unless requires additional time to
| parse than "if not"
|
| 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)
| enw wrote:
| 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".
| ravenstine wrote:
| 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.
| 8note wrote:
| Why bother with loop, continue, and break when you can have
| a more generic if+goto that can handle all the cases?
|
| You can simulate the loop behaviour if that's what you
| really want
| ravenstine wrote:
| 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.
| KMag wrote:
| 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.
| systems_glitch wrote:
| 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.
| welder wrote:
| 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'.
| nickelcitymario wrote:
| 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.)
| philote wrote:
| 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.
| micromacrofoot wrote:
| "if" is almost always easier to reason with, "unless" _can_ be
| elegant, but it 's so often misused that it doesn't really
| matter
| nickelcitymario wrote:
| 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.
| micromacrofoot wrote:
| 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.
| burke wrote:
| On this note: I'm sad ruby style guides generally ban "and"
| and "or". raise("a long error string")
| unless valid
|
| This reads much worse, when the string pushes the line near
| max width, than: valid or raise("..
|
| Of course it's another idiom to learn but it's not a
| difficult one when used simply.
| klodolph wrote:
| That's a very Perl idiom, did you previously write Perl?
| graywh wrote:
| the 2nd form implicitly returns the value of valid if
| it's truthy and nil if it's falsey; the 1st form always
| returns nil
| taeric wrote:
| 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.
| dyingkneepad wrote:
| 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.
| layer8 wrote:
| How about if you could write _except if_ instead of _unless_?
| bluedino wrote:
| _unless_ is one of those things I have to read 2-3 times and it
| totally bogs me down.
| 4pkjai wrote:
| I have a similar problem with list.filterNot() in Kotlin
| wruza wrote:
| Just reread _until_ you get it.
| layer8 wrote:
| Admittedly, _until_ (as the negation of _while_ for loops)
| tends to be more straightforward to grasp than _unless_.
| nickelcitymario wrote:
| 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?
| llimllib wrote:
| I feel like I have read if statements so many times that I
| have fast pattern matching circuits in my brain for them.
|
| 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.
| areichert wrote:
| 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
| nickelcitymario wrote:
| That makes sense!
| mathstuf wrote:
| 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.
| eloisius wrote:
| 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 do_something unless
| already_done?
| pantulis wrote:
| 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.
| gnufied wrote:
| 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.
| hosh wrote:
| 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?
| mjevans wrote:
| Perl also had that delayed syntax check style as an
| option and I HATED IT.
|
| THING if logical condition
|
| Filter First is far better self-documentation: if
| condition THING
| layer8 wrote:
| 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.
| hosh wrote:
| 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.
| [deleted]
| [deleted]
| RestlessMind wrote:
| I think it is also an issue of familiarity with English.
| Not all developers are fluent in English.
| peruvian wrote:
| 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.
| chrisandchris wrote:
| 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.
| kuratkull wrote:
| '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.
| geuis wrote:
| 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.
| class4behavior wrote:
| 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.
| JasonFruit wrote:
| You've demonstrated that it is trivially replaced by 'if' and
| negation. I think that's almost the definition of inelegant.
| akira2501 wrote:
| Go to the store and get milk, unless we already have some.
|
| Go to the store and get milk, if not we already have some.
| aaronbrethorst wrote:
| 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).
| nickelcitymario wrote:
| 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.
| ajmurmann wrote:
| The best example of vocabulary size and its tradeoffs this
| is the Guy Steele talk "Growing a Language". One of the
| best talks ever given.
| slowmovintarget wrote:
| Unconscious clarity trumps literary fluidity when reading
| code.
| [deleted]
| guitarbill wrote:
| > 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"...
| KMag wrote:
| 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.
| nickelcitymario wrote:
| 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!
| layer8 wrote:
| By the same token, using _until_ instead of _while_ and
| negation would be inelegant, but I think _until_ is less of a
| stumble block than _unless_.
| jewel wrote:
| 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.
| scruple wrote:
| Equivalent in output but not in implementation /
| performance. Does that matter? Not usually, no, but it
| depends.
| eloisius wrote:
| Not exactly the same. It's been a while, but if I recall,
| count takes a predicate block so you can do things like
| `numbers.count { |n| n.even? }`
| vidarh wrote:
| 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).
| chillfox wrote:
| Negation makes code harder to read and understand.
| nickelcitymario wrote:
| 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.
| lsaferite wrote:
| > 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).
| petre wrote:
| Maybe he means unless this and|or|xor that. That's what I
| use it for rather than negate every paraneter.
| layer8 wrote:
| Sometimes adding a temporary boolean variable is a good
| way to resolve a double (or single) negative.
| chillfox wrote:
| 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.
| asdajksah2123 wrote:
| 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.
| mattarm wrote:
| > 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.
| shakow wrote:
| 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.
| JasonFruit wrote:
| 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'.
| nine_k wrote:
| 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.
| shakow wrote:
| > 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.
| [deleted]
| nine_k wrote:
| 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.
| hosh wrote:
| That's how I see it as well. Also, if you need to tag on more
| conditions, convert it to an `if`
|
| The `unless` is idiomatic to the Ruby way of thinking.
| smeagull wrote:
| Should I read the damn article or not? I still have no idea
| j33zusjuice wrote:
| "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."
| topaz0 wrote:
| 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.
| makoto12 wrote:
| 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.
| quickthrower2 wrote:
| 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`.
| layer8 wrote:
| You're missing that less is more. ;)
| _moof wrote:
| 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."
| xcambar wrote:
| Sure. Except for every single existing use case of the word.
___________________________________________________________________
(page generated 2022-12-13 23:02 UTC)