Yield does not take a block

But a good inline cache implementation should have pretty small overhead,
and is far easier than attempting to make inferences about the types of
objects.

Ultimately I don't see why a method call a.foo() can't be compiled into
something like this:

     /* call a.foo() */

     static int md1234;
     static VALUE *old_class1234;
     static VALUE *fn(void);

     if (methods_defined != md1234 ||
         (klass = CLASS_OF(a)) != old_class1234)
     {
         fn1234 = method_find(a, "foo");
         md1234 = methods_defined;
         old_class1234 = klass;
     }
     fn1234();

"methods_defined" is a global variable incremented every time a method is
defined, to invalidate all caches. The normal case would be just a few
compares before calling the cached function pointer.

Anyway, there are other things in Ruby which are equally big overheads, and
just as difficult to optimise out. For example,

    10.times do
      puts "hello"
    end

generates a new String object containing "hello" each time round the loop,
which has to be garbage-collected. You can't re-use the same object unless
you can be sure that no references to it have been kept anywhere else.

There are both benefits and costs associated with a highly dynamic language
- but given that CPUs are so cheap, and programmer time is so expensive, I
think it's reasonable to go the Ruby way.

Regards,

Brian.

···

On Thu, Jun 30, 2005 at 01:59:27AM +0900, Eric Mahurin wrote:

--- Daniel Brockman <daniel@brockman.se> wrote:
> Eric Mahurin <eric_mahurin@yahoo.com> writes:
>
> > I think the destructive modification of a class and of an
> object's
> > class (making its class a singleton) are the main culprits.
>
> However, I ``destructively'' modify standard library classes
> and
> modules all the time. This is a major selling point for
> Ruby.

I'm not going to argue that it is not useful, because it is and
I use it. I'm just saying that being able to modify a class
and the (singleton) class of an object at runtime will prohibit
some amount of optimization within ruby.

I may actually prefer the underscore; I'm not really sure. I know I
prefer `<>' over `@', and maybe I shouldn't have mentioned the latter.

What do other people think?

alright, all you party people in the house, take note of my syntax:

when i use the underscore or "_" symbol it's in lieu of what i'd
normally UNDERLINE in a full-blown wordprocessor, because the
bare-bones nature of google's posting mini-app doesn't allow it. when
i want to emphasize the word "duh", i'll type an underscore before and
after, e.g. _duh_. when i want to interject a thought within a
sentence -- like this -- then i use the hyphen symbol.

i'm starting to see more and more so-called journalists using the
underscore instead of the hyphen symbol and thereby confusing my
carefully considered system of syntax. besides, it's driving me up the
wall and it must stop. if you refuse to stop the underscore-for-hyphen
nonsense despite my reasonable request, any goldfish you may or may not
have in your possession will be eaten alive

(p.s. i was thinking of adding a goldfish rape threat in there, but i'm
afraid senator man-on-dog will then be obsessing over man-on-sushi
sexual abnormalities for years henceforth. poor thing has enough to
worry about these days and i'm not that cruel, you know.)

Eric Mahurin wrote:

Having the yield keyword does
make it a little more difficult.

Actually, it makes it a lot more difficult. Consider:

irb(main):039:0> def blah
irb(main):040:1> eval "yield", binding
irb(main):041:1> end
=> nil
irb(main):042:0> blah { puts 5 }
5
=> nil

In any case, I don't have a strong opinion on the "arity" of blocks. I *do* have a fairly strong opinion that consistency should be favored wherever possible, but nothing real to back it up, other than that (the lack of) it is what I dislike most about Java (primitives, null, Serializable, java.lang...), and it is what I like most about Ruby.

As it stands now, this code block is
actually statically typed to Proc and not just an object that
responds to call and arity. I would prefer it to be any old
duck that can call and arity.

Agreed. That code be done without changing any of the current syntax, too.

irb(main):047:0> blah(&proc{puts 5})
5
=> nil

irb(main):048:0> p = Object.new
=> #<Object:0x2b31990>
irb(main):049:0> class << p
irb(main):050:1> def call
irb(main):051:2> puts 5
irb(main):052:2> end
irb(main):053:1> end
=> nil
irb(main):054:0> blah(&p)
TypeError: wrong argument type Object (expected Proc)
        from (irb):54

Boo. :frowning:

Devin
But yay, Ruby, in general.

Also, yay for just having an irb session sitting around in my taskbar. Does that make me a packrat?

···

from :0

The non-destructive version of this would be (simple
inheritance):

class MyNumeric < Numeric; def infinite?;false;end;end

I know that is not what you wanted and not nearly as useful. I
was just making the point that this useful behavior (modifying
classes at run-time) does come at a cost: it ties ruby to a
very dynamic object model that makes it difficult for ruby to
do certain types of optimizations.

···

--- Daniel Brockman <daniel@brockman.se> wrote:

You didn't respond to my question:

>> I don't see how returning a new class could be useful in
any way.
>> For example, what should happen if you say this?
>>
>> class Numeric ; def infinite? ; false end end

__________________________________
Yahoo! Mail Mobile
Take Yahoo! Mail with you! Check email on your mobile phone.
http://mobile.yahoo.com/learn/mail

Eric Mahurin wrote:

You could say the same thing about passing too many arguments
to a method. Why does Ruby check this case now?

I think a another similar question is why ruby doesn't allow you to declare the variables you're actually planning to use in a given context, allowing the system to give a helpful error if you accidentally mistype one of them, instead of leaving you to track down why variables don't have the value you expect.

Actually, it's not really a question, as I know the answer: the language developers have a religious objection to declarations, and think nobody should be allowed to use them, even if they want to. (See <URL:RCRS)

Why is it good to have to declare the arguments you expect, but bad to have to declare the variables or code blocks you expect? I don't know...

> I have no idea what this has to do with static typing.

Probably nothing, though you could wax philosophical over whether a block of code is a 'type' or not. Variable declaration has nothing to do with static typing either; however, some people seem to see everything as a clandestine attempt to introduce static typing... It's some kind of Post Java Trauma Disorder I think.

mathew

Daniel Amelang <daniel.amelang@gmail.com> writes:

Well, let's look at what our code looks like now vs. how it
would look:

Good idea.

# Current way
def meth(num)
  yield(num) if block_given?
end

meth 42 { |num| puts num }

Actually, that would have to be either this

   meth 42 do |num| puts num end

or this,

   meth(42) { |num| puts num }

since this

   meth 42 { |num| puts num }

is syntactically treated as this,

   meth (42 { |num| puts num })

which makes no sense. (You can argue that it does not make sense to
treat the code as nonsense on purpose, when there is really only one
reasonable interpretation. But then you have this

   meth 42.factorial { |num| puts num }

which has two reasonable interpretations, and the one Ruby takes
conflicts with the one needed for the original code to make sense.)

# Unified block/proc way
def meth(num, block=nil)
  block.call(num) if block
end

meth 42, { |num| puts num }

Nothing too strange, except for that comma in the argument list when
you call the method, since the block is now just a regular parameter.

This is actually an interesting comparison:

   meth(42) { |num| puts num }

   meth 42, { |num| puts num }

I know everyone will jump the opportunity to scream that the first one
is better in every way. But I don't think it's a clear-cut winner.
(Except when you need to chain more calls onto it --- read on.)

So when you call 'inject' now, it'd look like this:

sum = [1,2,3].inject 0, { |s, n| s + n }

That comma does look a little funny. Not a big deal, though.

How about this?

   average = [1,2,3].inject(0) { |s, n| s + n }.to_f / [1,2,3].size

You'd need to write that like so,

   average = [1,2,3].inject(0, { |s, n| s + n }).to_f / [1,2,3].size

unless we kept the old syntax as sugar. On the other hand, I don't
think there would be any problem in doing so. That is, this code

   foo(bar) { baz }

would be syntactic sugar for passing `bar' and `{ baz }' to `foo'.

Without the sugar, chaining method calls onto method calls with long
blocks would get pretty ugly. This cutie

   moomin snufkin do |a, b, c|
     snork.snork.snork.snork
     snork.snork.snork.snork
     snork.snork.snork.snork
   end.frobnicate

would turn into this

   moomin(snufkin, do |a, b, c|
     snork.snork.snork.snork
     snork.snork.snork.snork
     snork.snork.snork.snork
   end).frobnicate

(I'm assuming `do |x| y end' would be the same as `{ |x| y }'.)

I personally think method calls chained onto long blocks looks bad,
and I try to avoid it myself. But there are probably people who love
doing it, and who would hate it if it started to look even worse.

Note that this would be no problem even without the sugar ---

   moomin snufkin do |a, b, c|
     snork.snork.snork.snork
     snork.snork.snork.snork
     snork.snork.snork.snork
   end

it would just get an extra comma:

   moomin snufkin, do |a, b, c|
     snork.snork.snork.snork
     snork.snork.snork.snork
     snork.snork.snork.snork
   end

Seriously, though, getting rid of the yield keyword, block_given?, the
whole & thing for converting between blocks/procs and the concept of
blocks now being just regular parameters is a big change. The result
would border on a whole different language.

I agree that it is a very big change, but I wouldn't go so far as to
say it would make a different language. Adam is right that Ruby has
been shifting more and more towards this, to the point where Ruby 1.9
can make you think the block syntax looks like an historic quirk.

It is _conceptually_ pleasing to unify them. Does it really make our
lives easier?

I would like to know this as well.

The best example I can think of is this,

   gizmos.find({ || Gizmo.new :foo => true }) { |x| x.foo? }

which would turn into this,

   gizmos.find { || Gizmo.new :foo => true }, { |x| x.foo? }

which I think is an extremely minor improvement.

And what about this syntax?

   def foo *args, &block ; ... end

I guess that'd have to become something like this,

   def foo *args ; block = args.pop end

which is starting to look suspiciously much like Perl.

Maybe this syntax could be adopted?

   def foo a, b, *args, c, d; ... end

That is, at least four arguments, and any extra ones in the the middle
get splatted into `args'. I think it makes sense. Then we'd have

   def foo *args, block ; ... end

I think this is an interesting discussion. It's definitely good food
for thought. But, of course, we're just brainstorming.

···

--
Daniel Brockman <daniel@brockman.se>

I want that too. It would be nice for the = method where the
value is always the last argument. Or any method where you
want optional arguments first or in the middle.

In general, this:

def foo a, b, c=x, d=y, *other, e, f
    ...
end

should be equivalent to:

def foo a, b, *remaining
    e,f = remaining.slice!(-2,2)
    c = remaining.empty? ? x : remaining.shift
    d = remaining.empty? ? y : remaining.shift
    other = remaining
    ...
end

Want to submit an RCR for this? I've already done my fair
share.

···

--- Daniel Brockman <daniel@brockman.se> wrote:

Maybe this syntax could be adopted?

   def foo a, b, *args, c, d; ... end

____________________________________________________
Yahoo! Sports
Rekindle the Rivalries. Sign up for Fantasy Football

Eric Mahurin <eric_mahurin@yahoo.com> writes:

Maybe this syntax could be adopted?

   def foo a, b, *args, c, d; ... end

I want that too. It would be nice for the = method
where the value is always the last argument.

Yeah, that's a good example. Does anyone have another?

Or any method where you want optional arguments first or
in the middle.

In general, this:

def foo a, b, c=x, d=y, *other, e, f
    ...
end

should be equivalent to:

def foo a, b, *remaining
    e,f = remaining.slice!(-2,2)
    c = remaining.empty? ? x : remaining.shift
    d = remaining.empty? ? y : remaining.shift
    other = remaining
    ...
end

Want to submit an RCR for this? I've already done my fair share.

Fair enough. I'll wait a few days to see what happens to this thread,
and then I'll probably submit one.

···

Daniel Brockman <daniel@brockman.se> wrote:

--
Daniel Brockman <daniel@brockman.se>