Nil? takes much time

Hello all.

In one my class I’ve had very simple method:


def stored?
!@db.nil?
end

And I’ve suddenly noticed (due to profile) that nil? Takes a significant
amount of time here.

Redefining the above method like

def stored?
@db
end

(in if’s it works good) speedups the entire program.

I’m a bit surprized :slight_smile:

Victor.

On Apr 27, 2006, at 6:49 PM, Victor S. wrote:

And I’ve suddenly noticed (due to profile) that nil? Takes a

I’m a bit surprized :slight_smile:

If you think about it, it’s not all that surprising. false and nil
are both immediate values, this means its very quick to check if
something is not false or nil and therefore true. .nil? sends a
message. Sending a message involves

  1. interning the symbol :nil?. In this case that’s done at compile
    time, so no biggee

  2. Check if #nil? is in the object’s singleton class?
    2a) yes? Ok, create a stack frame execute the body of the method
    2b) no? Check the class of the object for #nil?
    Is it there? yes: ok allocate stack frame and execute the body
    no: Traverse the inheritance tree until we find it.

Sending a message is proportional to the levels of inheritance
(including modules) between the objects class and the first parent
class that implements the message plus the overhead of invoking a
method (allocating stack frame, setting self, etc.)

if @db
end

can be done as in pseudo-C code as

if ( @db != Qnil && @db != Qfalse ) {
}

versus:

if ( send(@db, :nil?) ) {
}

VALUE send(obj, message) {
if ( has_singleton(obj) ) {
if ( instance_respond(singleton_class_of(obj), message) ) {
return invoke_method(singleton_class_of(obj), obj, message);
}
}
if ( instance_respond(obj->class, message) {
return invoke_method(obj->class, obj, message);
}

  return send(upcast(obj, obj->class->superclass), message);

}

This isn’t real ruby/C code, and I’m sure the real thing uses
iteration instead of recursion, but you get the idea

amount of time here.

If you think about it, it’s not all that surprising. false and nil
are both immediate values, this means its very quick to check if
something is not false or nil and therefore true. .nil? sends a
message. Sending a message involves

[skip]

From one side, you are right (and I’ve must understand all above in
myself).
What is really unpleasant - is to see how can “infrastructure” code slow
down the program. The effect “nil? is slower then direct if” is
waitable.
What is UNwaitable - that nil? is noticable slower (in profile report
it
was fifth line from top). I hope thing would go better in next ruby’s
version.

Offtopic: BTW, can somebody comment on following questions:

  1. How much 1.9 faster than 1.8.4, and how much it stable?
  2. When can we wait for Rite?

Thanks.

Victor.

2006/4/28, Victor S. [email protected]:

Offtopic: BTW, can somebody comment on following questions:

  1. How much 1.9 faster than 1.8.4, and how much it stable?

There might not be an easier answer to that: could be that some
applications are faster and some slower.

  1. When can we wait for Rite?

Any time. :wink:

Kind regards

robert