The "!" and "?" characters

One of the things I like about Ruby is that it can use ! and ? in method
names. However, it seems that there are still limits to what can be
done.

I need a ‘factorial’ method, and I thought it’d be cute if the syntax was
“n.!” because it’s so close to “n!”. But Ruby doesn’t let me do that.

This one works:

class Fixnum
def f # Factorial
self < 0 and return -1 # Error code.
self ==0 and return 1
self * (self-1).f
end
end
5.f
=> 120

This is cool. But it’d be cooler if I could write ‘def !’ and ‘5.!’.
But ‘def !’ causes a parse error.

Now my question:
Does anyone know why ‘def !’ causes a parse error?

Thanks.

···


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

quintessence: quintessence (kwin-TES-ens) noun

  1. The pure, concentrated essence.

It’s a boolean operation, and they can’t be redefined (ditto ‘and’, ‘or’,
‘&&’, ‘||’, ‘not’)

Regards,

Brian.

···

On Wed, Apr 09, 2003 at 07:18:39AM +0900, Daniel Carrera wrote:

Does anyone know why ‘def !’ causes a parse error?

This is cool. But it’d be cooler if I could write ‘def !’ and ‘5.!’.
But ‘def !’ causes a parse error.

Now my question:
Does anyone know why ‘def !’ causes a parse error?

···

----- Original Message -----
From: “Daniel Carrera” dcarrera@math.umd.edu


Because it’s interpreting !' asnot’, I think. You can usually get around
these problems by sending symbols, but `:!’ gives a parse error. You can
usually get around those problems by interning a string:

irb(main):001:0> class Integer
irb(main):002:1> define_method (’!’.intern) {self *
(self-1).send(’!’.intern)}
irb(main):003:1> end
=> #Proc:0x400d3234@:2(irb)
irb(main):004:0> 5.send (’!’.intern)
Segmentation fault

Oops.

Hmmm…

Chris

For one thing, it’s an operator (the “not” operator).

Secondly, I don’t think it’s one of those operators
that can be overloaded.

Thirdly, if you are thinking of the “!” as in compact!
as being part of the name, I’d suggest thinking of it
as a suffix instead. (Yes, it is part of the name
in that “foo” and “foo!” and “foo?” are different
methods. But the ! or ? can appear only at the end
of the method name, not in the middle and certainly
not at the beginning.

In short: It just doesn’t work that way.

Hal

···

----- Original Message -----
From: “Daniel Carrera” dcarrera@math.umd.edu
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Tuesday, April 08, 2003 5:18 PM
Subject: The “!” and “?” characters.

Now my question:
Does anyone know why ‘def !’ causes a parse error?

There’s a workaround:

batsman@kodos:/tmp$ expand -t2 a.rb
class Fixnum
def fact
self < 0 and return -1 # Error code.
self ==0 and return 1
self * (self-1).fact
end
alias_method “!”, :fact
end
p Fixnum.instance_methods.sort

batsman@kodos:/tmp$ ruby a.rb
[“!”, “%”, “&”, “*”, “**”, “+”, “-”, “-@”, “/”, “<”, “<<”, “<=”, “<=>”,
“==”, “>”, “>=”, “>>”, “”, “^”, “abs”, “divmod”, “downto”, “fact”,
“id2name”, “modulo”, “next”, “size”, “step”, “succ”, “times”, “to_f”,
“to_s”, “type”, “upto”, “zero?”, “|”, “~”]

However…
batsman@kodos:/tmp$ expand -t2 a.rb
class Fixnum
def fact
self < 0 and return -1 # Error code.
self ==0 and return 1
self * (self-1).fact
end
alias_method “!”, :fact
end
p Fixnum.instance_methods.sort
p 5.!
batsman@kodos:/tmp$ ruby a.rb
a.rb:10: parse error

I’ve been reading parse.y for a while and see no way ‘!’ could be used
as an identifier alone, Ruby will try to begin an expression using
expr := ‘!’ command_call
or an argument with
arg := ‘!’ arg

···

On Wed, Apr 09, 2003 at 07:18:39AM +0900, Daniel Carrera wrote:

One of the things I like about Ruby is that it can use ! and ? in method
names. However, it seems that there are still limits to what can be
done.

I need a ‘factorial’ method, and I thought it’d be cute if the syntax was
“n.!” because it’s so close to “n!”. But Ruby doesn’t let me do that.

This one works:

class Fixnum
def f # Factorial
self < 0 and return -1 # Error code.
self ==0 and return 1
self * (self-1).f
end
end
5.f
=> 120

This is cool. But it’d be cooler if I could write ‘def !’ and ‘5.!’.
But ‘def !’ causes a parse error.

Now my question:
Does anyone know why ‘def !’ causes a parse error?


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Linux: because a PC is a terrible thing to waste
– ksh@cis.ufl.edu put this on Tshirts in '93

Chris Pine wrote:

From: “Daniel Carrera” dcarrera@math.umd.edu

This is cool. But it’d be cooler if I could write ‘def !’ and ‘5.!’.
But ‘def !’ causes a parse error.

Now my question:
Does anyone know why ‘def !’ causes a parse error?

Because it’s interpreting !' as not’, I think. You can usually get around
these problems by sending symbols, but `:!’ gives a parse error. You can
usually get around those problems by interning a string:

irb(main):001:0> class Integer
irb(main):002:1> define_method (‘!’.intern) {self *
(self-1).send(‘!’.intern)}
irb(main):003:1> end
=> #Proc:0x400d3234@:2(irb)
irb(main):004:0> 5.send (‘!’.intern)
Segmentation fault

Oops.

Hmmm…

Chris

With a test for the self==1 case, it works…

class Integer
define_method (:‘!’) do
self == 1 ? 1 : self * (self-1).send(:‘!’)
end
end

p(5.send(:‘!’)) # ==> 120

but I dont think there’s any way to call #! except with #send, and that
ain’t pretty.

···

----- Original Message -----

Well, I don’t know why that other code segfaulted (ideas, anyone?), but this
works:

irb(main):010:0> class Integer
irb(main):011:1> define_method(’!’) do
irb(main):012:2* raise ‘oops’ if self < 0
irb(main):013:2> break 1 if self == 0
irb(main):014:2> (self-1).send(’!’) * self
irb(main):015:2> end
irb(main):016:1> end
=> #Proc:0x401e5f88@:11(irb)
irb(main):017:0> 5.send(’!’)
=> 120

Perhaps not as satisfying for you, though, huh?

:slight_smile:

Chris

Does anyone know why ‘def !’ causes a parse error?

It’s a boolean operation, and they can’t be redefined (ditto ‘and’, ‘or’,
‘&&’, ‘||’, ‘not’)

Oops. Okay, I’m being dumb today.

Thanks.

···


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

quintessence: quintessence (kwin-TES-ens) noun

  1. The pure, concentrated essence.

You could always compromise and ust
def _!

This one works:

class Fixnum
def f # Factorial
self < 0 and return -1 # Error code.
self ==0 and return 1
self * (self-1).f
end
end
5.f
=> 120

5._!
=> 120

···

On Wednesday, 9 April 2003 at 8:05:20 +0900, Mauricio Fernández wrote:

On Wed, Apr 09, 2003 at 07:18:39AM +0900, Daniel Carrera wrote:


Jim Freeze

Fuch’s Warning:
If you actually look like your passport photo, you aren’t well
enough to travel.

Hi,

···

In message “Re: The “!” and “?” characters.” on 03/04/09, “Chris Pine” nemo@hellotree.com writes:

irb(main):001:0> class Integer
irb(main):002:1> define_method (‘!’.intern) {self *
(self-1).send(‘!’.intern)}
irb(main):003:1> end
=> #Proc:0x400d3234@:2(irb)
irb(main):004:0> 5.send (‘!’.intern)
Segmentation fault

Segmentation fault was caused by a GC bug. Thank you for finding.

						matz.

By the way why not allow to define new operators, like in prolog and
sml?

Gergo

···


±[ Kontra, Gergelykgergely@mcl.hu PhD student Room IB113 ]---------+

http://www.mcl.hu/~kgergely “Olyan langesz vagyok, hogy |
Mobil:(+36 20) 356 9656 ICQ: 175564914 poroltoval kellene jarnom” |
±–Magyar php mirror es magyar php dokumentacio: http://hu.php.net---+

With a test for the self==1 case, it works…

···

----- Original Message -----
From: “Joel VanderWerf” vjoel@PATH.Berkeley.EDU


Yeah, that was embarrassing…

Still, why a segfault and not a stack overflow?

Chris

Segmentation fault was caused by a GC bug. Thank you for finding.

···

----- Original Message -----
From: “Yukihiro Matsumoto” matz@ruby-lang.org


My (dis)pleasure.

:slight_smile:

Chris

I’ve talked about this from time to time on #ruby-lang. It’s not
going to happen, unfortunately, but it would be nice. In Lisp, you
can define macros (note: not anything like #define macros; same
word, different meaning), and even modify the reader (lisp’s
equivalent of a parser), so you can add new literals and basically
anything else. For instance, while Common Lisp defines no regexp
literal (like /^foo$/), you could easily add one.

Ruby uses a yacc parser though, and this sort of parser is not mutable.
For a syntax as complex as Ruby’s, this is nice, since it’s easier to
write, maintain, and probably runs faster. But it means you can’t
define a new operator, since both the tokens and parser were defined at
compile time.

At least, this is what I’ve gathered, if I’m wrong, someone please
correct my mistake.

···

On Sat, 12 Apr 2003 04:46:05 +0900 KONTRA Gergely kgergely@mlabdial.hit.bme.hu wrote:

By the way why not allow to define new operators, like in prolog and
sml?

Ryan Pavlik rpav@users.sf.net

“That’s the first pratical line of thinking to
come out of your word hole since we first met.” - 8BT

Hi,

···

In message “Re: The “!” and “?” characters.” on 03/04/12, KONTRA Gergely kgergely@mlabdial.hit.bme.hu writes:

By the way why not allow to define new operators, like in prolog and
sml?

(a) it would make the parser hard to write, hard to maintain, and
slow.

(b) it would make syntax vary program to program, which would make
programs hard to read.

And (b) is also the reason not to have macros in Ruby.

						matz.

Hi,

···

At Wed, 9 Apr 2003 07:56:15 +0900, Chris Pine wrote:

Still, why a segfault and not a stack overflow?

When stack really overflowed, OS kills the process immediately.
User program can do nothing at all. Ruby tries to prevent it
but not perfect.


Nobu Nakada

You’re the chief but … macros make it actually easier to read programs.
Just think of cond in lisp. But … you’re the chief :slight_smile:

-martin

···

On Sat, Apr 12, 2003 at 08:50:58PM +0900, Yukihiro Matsumoto wrote:

By the way why not allow to define new operators, like in prolog and
sml?

(a) it would make the parser hard to write, hard to maintain, and
slow.

(b) it would make syntax vary program to program, which would make
programs hard to read.

And (b) is also the reason not to have macros in Ruby.

> (b) it would make syntax vary program to program, which would make > programs hard to read. > > And (b) is also the reason _not_ to have macros in Ruby.

I wonder at this… Lisp has macros, and they don’t make it harder
to read. Actually, Lisp-style macros applied to ruby would be somewhat
more like a simple eval, where you might go (in pseodoruby):

defmacro c_for(st1, st2, st3)
    #{st1}
    while(#{st2})
        yield
        #{st3}
    end
end

Now you can go:

c_for(i = 0, i < 200, i += 1) {
    ...
}

The advantage to this over eval() is probably apparent:

*  The macro can be mostly preparsed, making execution faster
   than eval

*  The statement import allows for a much more natual syntax

*  The above is _more_ readable, in both creation and use,
   than an equivalent eval.

Would it be possible for one to abuse defmacro in ruby? Of course.
It’s possible to abuse any language feature: blocks, continuations,
exceptions, catch/throw, etc. But it would be pretty useful, too.

This doesn’t address the reader aspect. Doing that, and allowing one
to add operators, would probably fall under (a), although there may
be some brilliant scheme to avoid it. (OTOH, with byte compilation
that might be a different story. :wink:

There is a single parser I know of that allows one to add such syntax,
and that’s the Lout typesetting package, where you can define a function
with @Left and @Right parameters, and function names can be anything
(including “operators”), so you can:

def = @Left { x } @Right { y } {
x equals y
}

foo = bar % outputs “foo equals bar”… although you could
% of course make it do more interesting things :wink:

With perhaps some generalization and limitation, this could be made
to work with yacc. Of course, it would require macros in order to
accomplish some things like assignment:

defmacro (var) += (var2)
    #{var} = #{var} + #{var2}
end

Or Everyone’s Favorite Missing Operator ( :wink: ):

defmacro (var)++
    #{var} += 1
end

Anyhow, I’m kinda wandering off here, but thinking about this, it
just seems kinda neat.

later,

···

On Sat, 12 Apr 2003 20:50:58 +0900 matz@ruby-lang.org (Yukihiro Matsumoto) wrote:


Ryan Pavlik rpav@users.sf.net

“My plans are always practical! It’s the laws of
physics that get in the way of my success.” - 8BT

Watch matz’s presentation at LL2 for some real-life discussions on that :slight_smile:
It’s available at http://www.bebear.net/ll2/LL2_Ruby.mov .

···

On Sat, Apr 12, 2003 at 10:59:18PM +0900, Martin Weber wrote:

On Sat, Apr 12, 2003 at 08:50:58PM +0900, Yukihiro Matsumoto wrote:

By the way why not allow to define new operators, like in prolog and
sml?

(a) it would make the parser hard to write, hard to maintain, and
slow.

(b) it would make syntax vary program to program, which would make
programs hard to read.

And (b) is also the reason not to have macros in Ruby.

You’re the chief but … macros make it actually easier to read programs.
Just think of cond in lisp. But … you’re the chief :slight_smile:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

     Why use Windows when you can have air conditioning?
     Why use Windows, when you can leave through the door?
-- Konrad Blum

I wonder at this… Lisp has macros, and they don’t make it harder
to read.

Perhaps because it is impossible to make Lisp harder to read :-))

Actually, Lisp-style macros applied to ruby would be somewhat
more like a simple eval, where you might go (in pseodoruby):

defmacro c_for(st1, st2, st3)
    #{st1}
    while(#{st2})
        yield
        #{st3}
    end
end

c_for(i = 0, i < 200, i += 1) {
    ...
}

I’m not sure if that’s the best example, because you can do that anyway if
st1/st2/st3 are proc objects:

def c_for(st1, st2, st3)
    st1.call
    while(st2.call)
        yield
        st3.call
    end
end

i = nil
c_for(proc {i = 0}, proc {i < 10}, proc {i += 1}) do
    puts i
end

I’m not a Lisp hacker (I’ve tried and failed there), but are Lisp macros
more powerful than that?

Passing in a proc object means that it’s pre-parsed, oven-basted and
ready-to-run. Furthermore you can pass them around as first-class objects:

def make_c_for(st1, st2, st3)
    proc {
        st1.call
        while(st2.call)
            yield 
            st3.call
        end
    }
end

i = nil
myloop = make_c_for (proc {i = 0}, proc {i < 10}, proc {i += 1}) do
   puts i
end

myloop.call

This kind of function composition was something I saw quite a lot of when
trying to learn Lisp.

Regards,

Brian.

···

On Sun, Apr 13, 2003 at 01:04:53AM +0900, Ryan Pavlik wrote: