5

Very much an idle day-dream this but is it possible with some neat meta-programming trick to define a new logical operator in Ruby? I'd like to define a but operator.

For example, if I want to do something if x but not y is true I have to write something like:

if x and not y

But I would like to write

if x but not y

It should work exactly the same as and but would be down to the programmer to use sensibly to increase the legibility of code.

Russell
  • 12,261
  • 4
  • 52
  • 75
  • 3
    Not without a parser change. The semantics of the construct are unclear, IMO, without the `and`. – Dave Newton Nov 28 '11 at 14:57
  • Can you give an example of why you think the semantics are unclear? It would work exactly the same as `and`. The only difference is that it would *imply* that the logical value of `x` was != the logical value of `y`. – Russell Nov 28 '11 at 15:02
  • What would `if x but y` mean? It's not a technical issue, it's a "Dave doesn't think it's clear" issue--purely preferential. – Dave Newton Nov 28 '11 at 15:05
  • That would be an example of a BAD programmer abusing the construct. Maybe slightly better would be `unless x but y` - although it's still a bit rubbish. It basically fits well with the use case I describe in the question but not much else - which is why it's an idle daydream! – Russell Nov 28 '11 at 15:09
  • 1
    What I mean is, it's equally easy to abuse existing constructs: `unless not x and not !y` for example. – Russell Nov 28 '11 at 15:10
  • Like I said, purely preferential :) – Dave Newton Nov 28 '11 at 15:12
  • Very interesting discussion overall. For most of my career, I only knew about if, and, not, and or. Then I started using Perl and became familiar with 'unless'. At first, I thought 'unless' was unnecessary. Over time, it started to make sense to me. So who knows? Maybe 'but' will emerge as part of the lexicon as well... – Stephen Gross Nov 28 '11 at 15:48
  • Your example `unless not x and not !y` is unwieldy but still makes logical sense. `x but y` just doesn't parse into any logical form – Gareth Nov 28 '11 at 18:06
  • Fair enough, I'll concede that. I still don't think that diminishes it's (very slight) usefulness in the case of `x but not y`, and I still think if a code wrote `x but y` it would be them at fault for misusing the language rather than the language for providing that good old syntactic sugar. – Russell Nov 28 '11 at 21:46

3 Answers3

6

Without editing the Ruby parser and sources and compiling a new version of Ruby, you can't. If you want, you can use this ugly syntax:

class Object
  def but(other)
    self and other
  end
end

x.but (not y)

Note that you can't remove the parentheses or the space in this snippet. It will also shadow the functionality of the code to someone else reading your code. Don't do it.

Felixyz
  • 19,053
  • 14
  • 65
  • 60
Guilherme Bernal
  • 8,183
  • 25
  • 43
  • 3
    More importantly, this "solution" will always evaluate *both* `x` and `y` (no short circuit) and will do so in the *reverse order* (`y` then `x`). – Marc-André Lafortune Nov 28 '11 at 16:32
  • @Marc-AndréLafortune And that's probably the reason overriding `&&` and `||` is not possible (while overriding `&` and `|` is). – Mladen Jablanović Nov 28 '11 at 17:05
  • 1
    @MladenJablanović: You just have to define a set of operators (let's call them *lazy operators*) which get translated to `a.OP { b }` instead of `a.OP(b)`, then it would be perfectly fine to do override them. A couple of years ago, I re-implemented all of Ruby's boolean operators as message sends, and I even used the `RubySpec` testsuite to verify their correct behavior: https://GitHub.Com/JoergWMittag/B001e/ BTW: Please focus on the *actual* semantics of that code ... this was the first ever Ruby project I wrote, and the code is *terrible* :-) – Jörg W Mittag Nov 28 '11 at 17:28
  • 2
    I agree. The best part in this answer is don't do it. +1 – lucapette Nov 28 '11 at 20:29
2

If you really want to do this, try editing parse.y and recompiling Ruby. That's where Ruby's syntax is defined.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
  • Why I would say its not recommended for anything with practical application, I think the user could learn something from trying it. – AwDogsGo2Heaven Mar 10 '13 at 02:59
0

As others have already pointed out, you cannot define your own operators in Ruby. The set of operators is predefined and fixed. All you can do is influence the semantics of some of the existing operators (namely the ones that get translated into message sends) by responding to the appropriate messages.

But of course, you can implement a but method quite easily:

class Object
  def but
    self && yield
  end
end

Object.new.but { not true }
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653