Introducing Object#self

I just came across a situation where it would be extremely handy to have a method that returns the receiver.

Imagine the following example:

filter = %w(with_votes without_votes).include?(params[:filter]) ? params[:filter].to_sym : :self Idea.published.send(filter).all

The implementation would be pretty simple:

class Object   def self     self   end end

Should this be a part of Rails?

I just came across a situation where it would be extremely handy to

have a method that returns the receiver.

Imagine the following example:

filter = %w(with_votes without_votes).include?(params[:filter]) ?

params[:filter].to_sym : :self

Idea.published.send(filter).all

The implementation would be pretty simple:

class Object

def self

self

end

end

Should this be a part of Rails?

Doesn’t tap method in 1.9 do that already?

Anuj

Very similar.

tap will yield the block passed to it then return self:

def tap

yield self

self

end

Object#tap needs a block.

Joao

I just came across a situation where it would be extremely handy to have a method that returns the receiver.

Imagine the following example:

filter = %w(with_votes without_votes).include?(params[:filter]) ? params[:filter].to_sym : :self Idea.published.send(filter).all

The implementation would be pretty simple:

class Object def self self end end

Should this be a part of Rails?

Doesn't tap method in 1.9 do that already?

Object#tap requires a block.

Rails has Object#presence, which is

def presence   self if present? end

So for *most objects* it does what you want (except for empty arrays, strings, etc)

I wouldn’t call this use case where it would be “extremely handy”. Here is better code for it:

filters = Idea.scopes.keys & Array.wrap(params[:filter]).map(&:to_sym)

records = filters.inject(Idea.published) { |model, name| model.send(name) }.all

First bonus feature is that it knows about all your named scopes, you don’t have to specify them in the controller (business logic in your controller = wrong).

Another bonus feature — multiple filters can be given:

GET /resource?filter=foo&filter=bar

Third bonus feature is that we didn’t need to extend the language with a method that doesn’t do absolutely anything.

(Even tap does something and is incredibly useful.)

I'll admit mine was a bad example. However, the most common (only?) use case I could see for it is in fact with #send.

Your idea for filtering is great, by the way.

I'll admit mine was a bad example. However, the most common (only?) use case I could see for it is in fact with #send.

Your idea for filtering is great, by the way.

Instead of send you can use instance_eval. Where you'd do something like obj.send(x? ? :self : :other) you can do obj.instance_eval { x? ? self : other }

Cheers -foca

I won't comment on your use case, others have already done that.

However. I think naming the method self is potentially confusing, since self is a keyword which means the receiver of the current message.

class Foo

    def m(arg)        arg.self     end end

I'd have to think about what self meant anytime I read that.

Smalltalk has a similar method, which is usually used to end a cascade of message sends (something which ruby doesn't have).

   pt = Point.new x:1; y:2; yourself

A rather concocted example, but the point is that the yourself method returns the receiver, and is IMHO a much better method name.

By way of explanation, a semicolon after a message invocation indicates that the subsequent message is sent to the receiver of the preceding message, instead of the result of that mesage. so the above would be equivalent to:

tmp = Point.new tmp x: 1 tmp y: 2 pt = tmp yourself

(somehow managed to forget to hit send on this one yesterday. sigh.)

Smalltalk has a method Object#yourself which does just that. The most common use case is with cascaded message sends, but Ruby doesn't have those. I've wanted #yourself in Ruby now and then too. Since Matz was very familiar with Smalltalk when he created Ruby I assume he didn't think it was necessary, but it's one of the questions I always want to ask him but forget to when I get the chance.

+1

Also had the need for something like this in the past.

Object#presence won't cut it when you're short-circuiting some part of computation inside of the chained calls, for example this

@users.send(@admins_only ? :select : :presence, &:admin?).sort

will fail when @users array is blank.

Also isn't this function sort of OO version of Identity function - Wikipedia ?

Btw. the use cases like this could be made even simpler by adding/using Object#send_if

@users.send_if(@admins_only, :select, &:admin?).sort

And it looks like people have been doing this for quite a while already :slight_smile:

http://www.google.com/codesearch?q=lang%3Aruby+def\ssend_if

Why not rewrite that as:

if @admins_only   @users.select(&:admin?).sort else   @users.sort end

or even

@users = @users.select(&:admin?) if @admins_only @users.sort

I think that is infinitely easier to read and understand (it took me a while to figure out what the hell your code was doing). Just because you *can* make everything into a one-liner in Ruby, doesn't mean you *should*.

Also from the naming of the variables it sounds like you are doing this in the controller, that's the wrong place to do this sort of thing, imho. Put it in the model instead!

@users.readable_by(@user)

This clearly communicates what you are trying to achieve.

/Jonas

I fully support Jonas.

Anyway, what’s the track record of getting a language extension into Active Support if it’s not being used inside the framework? I’d say very low.

Never mind that example, I made it up just to illustrate the issue which was that the short-circuiting had to happen in the middle of long method chain and I didn't want to introduce local variable just for this optional filtering step:

SomeModel.some_scope.all.   group_by(&:user).<<optional filtering here >>.   map { ... }.sort_by(&:second).reverse.map(&:first)

Though I must admit this is hardcore and happened to my only once or twice :slight_smile:

As for "track record of getting a language extension into ActiveSupport if it's not being used inside the framework", here it is:

http://github.com/rails/rails/commit/51730792ca9

I wasn't talking about that specific code sample either. Long chaining of methods is an anti-pattern and we shouldn't be encouraging it. Put it in the model and decompose it.

/Jonas