Project

General

Profile

Actions

Feature #6373

closed

public #self

Added by trans (Thomas Sawyer) almost 12 years ago. Updated over 8 years ago.

Status:
Closed
Target version:
-
[ruby-core:44704]

Description

This was recently suggested to me as an extension:

class Object
  # An identity method that provides access to an object's 'self'.
  #
  # Example:
  #   [1,2,3,4,5,1,2,2,3].group_by(&:identity)
  #   #=> {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}
  #
  def identity
    self
  end
end

First, is such a method commonly useful enough to warrant existence?

Second, it makes me wonder if #self should be a public method in general.


Files

self.pdf (77.8 KB) self.pdf marcandre (Marc-Andre Lafortune), 08/31/2013 06:59 AM
itself.diff (1.87 KB) itself.diff rafaelfranca (Rafael França), 08/01/2014 06:22 PM

Related issues 1 (1 open0 closed)

Related to Ruby master - Feature #6817: Partial applicationAssignedmatz (Yukihiro Matsumoto)Actions

Updated by mame (Yusuke Endoh) almost 12 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

Updated by duerst (Martin Dürst) almost 12 years ago

#identity (or whatever it's called) is quite important in functional languages. It's handy to pass to another function that e.g. uses it as an argument to map,... So I think it's a good idea to add it.

The name should be identity or id (Haskell) or some such.

Making self public sounds impressive, but first, it doesn't expose anything new (it's the object itself, which is already accessible) an second, I feel it's the wrong name, because #idenity essentially only makes sense in locations in a program where the actual object isn't directly around.

Updated by headius (Charles Nutter) almost 12 years ago

At first I found this laughable, but then I realized there's no clear method you can call against an object that simply returns the object. It is a small thing, but turns out to be very useful.

For example, if you want a chain of method calls that successively transformation some data. Those transformations, in the form of folds or filters or what have you, may accept an object and return some new object by calling a method. In that case, the simplest transformation is to simply return the object unmodified. There is no such method on Object or BasicObject right now, so rather than having the uniformity of a method call you would need a special filter form that calls nothing and returns its one argument. Identity is an easy, simple functional form that should be available.

I would suggest it should be called self or similar, since it is a key core method nobody should ever override. But I do think there is utility in having it always available.

Updated by headius (Charles Nutter) almost 12 years ago

Actually, I just realized there is already a method you can call to just return the method itself, albeit in a really gross way: #tap.

obj.tap{} #returns obj; block is required and invoked

Updated by prijutme4ty (Ilya Vorontsov) almost 12 years ago

enum.map(&:identity) can be replaced with enum.to_a
But I think Object#identity is useful. Object#tap requires a block. It's not an option to use it in many cases. I can't imagine how to replace enum.group_by(&:identity) with tap instead of identity.

I think that tap method can be improved to be used without block yielding self. But for readability it'd be however aliased to identity.

__self__ looks like a method every programmer'd avoid.

Updated by matz (Yukihiro Matsumoto) almost 12 years ago

__id__ returns object_id number, identity here is supposed to return itself.
I agree with introducing method to return self, but not fully satisfied with the name 'identity'.
Any opinion?

Matz.

Updated by trans (Thomas Sawyer) almost 12 years ago

Public #self seems like the most obvious choice. Is there some reason not to use it?

Updated by regularfry (Alex Young) almost 12 years ago

On 28/04/2012 16:10, matz (Yukihiro Matsumoto) wrote:

Issue #6373 has been updated by matz (Yukihiro Matsumoto).

__id__ returns object_id number, identity here is supposed to return itself.
I agree with introducing method to return self, but not fully satisfied with the name 'identity'.
Any opinion?

"itself"?

--
Alex

Updated by pabloh (Pablo Herrero) almost 12 years ago

What about if we borrow #yourself message name from Smalltalk?

Updated by alexeymuranov (Alexey Muranov) almost 12 years ago

Thomas, i think an argument against public #self is that 'self' is a reserved word, which moreover is used more as an object name than as a method name. So 'self' would need to stop being a keyword and become a public 'predefined' method of BasicObject (it cannot be defined without the 'self' keyword, i guess).

I like #itself or #yourself, but i do not know which one is a proper way to talk to my objects.

Updated by trans (Thomas Sawyer) almost 12 years ago

Like many of Ruby's keywords, it can still be used to define a public method:

class X
  def self; "x"; end
end

x = X.new
x.self  #=> "x"

Updated by shevegen (Robert A. Heiler) almost 12 years ago

Perhaps Smalltalk has the best suggestion. :)

Updated by alexeymuranov (Alexey Muranov) almost 12 years ago

Another option: #the_self. The same number of symbols as in #yourself, but harder to type :(.

Updated by Eregon (Benoit Daloze) almost 12 years ago

On 28 April 2012 17:54, Alex Young wrote:

"itself"?

I agree, #itself is the best to me.

Updated by marcandre (Marc-Andre Lafortune) almost 12 years ago

I second the addition of Object#self.

For the objection that self is a keyword, so is class. And there wouldn't ever be a need to call self.self :-)

Do we need a slide-show for this?

Updated by trans (Thomas Sawyer) almost 12 years ago

Does it really need a slide? Does someone at developers meeting want to bring it up? It's such a simple thing. It's probably a one line addition to code to make self available as public method. Only question is name, which seems to me, why have different public name than private name? Go with #self. But if necessary for public/private names to differ, everyone seems okay with #itself.

Updated by alexeymuranov (Alexey Muranov) almost 12 years ago

I've heard that the underscore _ is commonly used for ignored block variables. Maybe this "public self" can be considered as an "ignored method", and called Object#_?

Updated by trans (Thomas Sawyer) almost 12 years ago

_ is used by irb. Also, I don't really see why. Code would look much more "perlish" using _.

Please, what's wrong with public #self?

Updated by alexeymuranov (Alexey Muranov) almost 12 years ago

trans (Thomas Sawyer) wrote:

Please, what's wrong with public #self?

Nothing, just was wondering how to use _ :). I didn't know IRB uses it.

Updated by citizen428 (Michael Kohl) over 11 years ago

FWIW, I'm the one who suggested this method as an addition to Facets, mainly for the reason headius mentions above, it's the simplest filter available. I'm still torn on the name, but for some reason #self didn't seem right. For my own extension library I finally went with #it.

Updated by citizen428 (Michael Kohl) over 11 years ago

i also found a previous issue where this behavior would come in handy: http://bugs.ruby-lang.org/issues/2172

Updated by alexeymuranov (Alexey Muranov) over 11 years ago

How about merging this with feature request #6721 for #yield_self?

Object#self can optionally accept a block, yield self to the block if block given, and return the result of the block. What do you think?

Updated by trans (Thomas Sawyer) over 11 years ago

Strikes me as a very good idea! I forgot about that. In Facets it is called #ergo. Essentially,

def ergo
  return yield(self) if block_given?
  self
end

Call it #self instead and we get two features for the price of none!

Not sure if should take additional *args or not, but it could.

Updated by Anonymous over 11 years ago

matz (Yukihiro Matsumoto) wrote:

__id__ returns object_id number, identity here is supposed to return itself.
I agree with introducing method to return self, but not fully satisfied with the name 'identity'.
Any opinion?

Matz.

I did some thinking, and there is hardly anything better than 'identity'.
'identity_function' would be hypercorrect, and 'id' is commonly understood
as identifier. In my personal library, I use 'ɪ' (small cap Unicode I) for
identity mapping, though...

Updated by alexeymuranov (Alexey Muranov) over 11 years ago

boris_stitnicky (Boris Stitnicky) wrote:

matz (Yukihiro Matsumoto) wrote:

__id__ returns object_id number, identity here is supposed to return itself.
I agree with introducing method to return self, but not fully satisfied with the name 'identity'.
Any opinion?

Matz.

I did some thinking, and there is hardly anything better than 'identity'.
'identity_function' would be hypercorrect, and 'id' is commonly understood
as identifier. In my personal library, I use 'ɪ' (small cap Unicode I) for
identity mapping, though...

ID as an identifier or a piece of identification and Id as the identity function are two different meanings, as far as i understand. Also it does not look to me like "method" and "function" have exactly the same semantics.

Updated by Anonymous over 11 years ago

On Fri, Aug 10, 2012 at 4:25 PM, matz (Yukihiro Matsumoto)
wrote:

__id__ returns object_id number, identity here is supposed to return itself.
I agree with introducing method to return self, but not fully satisfied with the name 'identity'.
Any opinion?

How about allowing Object#tap to take no block, simply returning self?
This syntactic sugar would allow

 this.tap

instead of

 this.tap {}

If a new method must be added, please for the love of sanity don't
call it id or identity or identifier. This space already chronically
overloaded by frameworks, the need for entities to have publically
visible identity notwithstanding.

Perhaps __object__, which would feel natural to anyone already
familiar with __id__? Failing that, Object#object, although I'd expect
this to break a fair amount of existing code. :-(

Ciao,
Sheldon.

Updated by trans (Thomas Sawyer) over 11 years ago

Why no answer for: "Why not just public #self"? Why add YAMS?

(YAM = Yet Another Method)

Updated by matz (Yukihiro Matsumoto) over 11 years ago

  • Status changed from Assigned to Feedback
  • Target version changed from 2.0.0 to 2.6

The point is when we see the code like:

[1,2,3,4,5,1,2,2,3].group_by(&:self)

sometimes it would be less intuitive that self refers elements in the array, not self in the scope.
I think this cause YAM syndrome here. We haven't met name consensus yet (as usual), so I postpone to next minor.

Matz.

Updated by laise (Alexey Chernenkov) almost 11 years ago

Quote: "I think that tap method can be improved to be used without block yielding self."

+1

It is a VERY usefull feature! Can't understand why #tap still need to be used with block only.

Updated by phluid61 (Matthew Kerwin) almost 11 years ago

laise (Alexey Chernenkov) wrote:

Quote: "I think that tap method can be improved to be used without block yielding self."

+1

It is a VERY usefull feature! Can't understand why #tap still need to be used with block only.

Because it's called "tap." Tap doesn't "return self", it taps into an execution flow, extracting an intermediate value for inspection without interrupting the original flow. The analogy is literally tapping a hole in a pipe, to extract liquid samples at various phases in a process. (Also think of tapping a phone line.) Changing its semantics to a straight-up "returns self" method would just make it idiosyncratic, instead of metaphoric.

Matz wrote:

The point is when we see the code like:

[1,2,3,4,5,1,2,2,3].group_by(&:self)

sometimes it would be less intuitive that self refers elements in the array, not self in the scope.

I have trouble imagining such a scenario. I actually think the some_array.group_by(&:self) example is a strong plus for this feature.

I'm also not entirely convinced it's really YAM, since 'self' is already a word in the language, all we're doing is pushing it from keyword to keyword+method, i.e. making it more easily accessible from outside the instance. Even more so since this use-case is really the only place it will ever show up; if there was another way to to_proc the 'self' keyword to make it easy to pass to a method like group_by I'd be for that as well/instead.

Updated by Anonymous almost 11 years ago

trans (SYSTEM ERROR) wrote:

Why no answer for: "Why not just public #self"? Why add YAMS?

(YAM = Yet Another Method)

Because explicit identity element is a VIP of the functional space.
Summary of the discussion thus far + my opinions follow:

Proposal: My opinion: Remark:
#self +1 proposed and defended by OP, objected by Matz
#identity +1 strong objection by Anonymous
#__id__ 0
#__self__ -1
#yourself -1
#itself +3
#_ -1
#the_self -1
#it -1
#__object__ -1
#id -1 not proposed, Anonymous strongly objects this option
#tap -2 me and phluid61 strongly object

I used to favor #identity, but today, I favor #itself. I already advertised this
method, and #ergo method (#6721) on http://stackoverflow.com/questions/16932711 ,
where these features are in demand. To make the naming decision more difficult,
let me append Freudian #ego to the list, which would go nicely with #ergo.

Actions #33

Updated by headius (Charles Nutter) almost 11 years ago

phluid61 (Matthew Kerwin) wrote:

laise (Alexey Chernenkov) wrote:

It is a VERY usefull feature! Can't understand why #tap still need to be used with block only.

Because it's called "tap." Tap doesn't "return self", it taps into an execution flow, extracting an intermediate value for inspection without interrupting the original flow. The analogy is literally tapping a hole in a pipe, to extract liquid samples at various phases in a process. (Also think of tapping a phone line.) Changing its semantics to a straight-up "returns self" method would just make it idiosyncratic, instead of metaphoric.

I still like #tap.

  1. It would only require removal of the block-yielding requirement.
  2. It's functionally equivalent to tapping into execution flow but doing nothing, as in tap {}. I think the objection that it no longer means we're tapping execution flow is a bit pedantic; we are tapping execution flow, but the only operation we seek is the reference to the object.

My favorite remains #self, but I can appreciate objections, especially confusion over "self" and "obj.self" and especially "self.self" if #self can be overridden. It does have the advantage that there's probably fewer libraries that define their own "self" method than any other suggestion here.

Other systems I know would use #identity. It also maps to functional programming language for a function that just returns its sole argument (in this case, the 0th argument, the object itself). I would support #identity as well.

Matz wrote:

The point is when we see the code like:

[1,2,3,4,5,1,2,2,3].group_by(&:self)

sometimes it would be less intuitive that self refers elements in the array, not self in the scope.

I have trouble imagining such a scenario. I actually think the some_array.group_by(&:self) example is a strong plus for this feature.

I'm also not entirely convinced it's really YAM, since 'self' is already a word in the language, all we're doing is pushing it from keyword to keyword+method, i.e. making it more easily accessible from outside the instance. Even more so since this use-case is really the only place it will ever show up; if there was another way to to_proc the 'self' keyword to make it easy to pass to a method like group_by I'd be for that as well/instead.

Another option based on matz's objection: #reference. We want a method that returns the reference to the object we're calling against. #reference seems logical.

[1,2,3,4,5,1,2,2,3].group_by(&:reference)

Variations on this might be #self_reference, #self_ref, #selfref. Also #self_object, #self_obj, #selfobj.

#self and #identity are probably the most likely to be guessed by a new user.

Actions #34

Updated by headius (Charles Nutter) almost 11 years ago

Another argument why "tap" is fine...

If tap were defined in a functional style, it would be simply

def tap(obj, &block)
  block.call(obj)
  obj
end

Anywhere you can pass a function you should be able to pass a no-op function, so tap could be defined as

def tap(obj, &block)
  block = proc{} unless block
  block.call(obj)
  obj
end

So defining tap such that it defaults to a no-op function (i.e. does not yield if block not given) seems perfectly valid to me.

Updated by phluid61 (Matthew Kerwin) almost 11 years ago

headius (Charles Nutter) wrote:

Another option based on matz's objection: #reference. We want a method that returns the reference to the object we're calling against. #reference seems logical.

[1,2,3,4,5,1,2,2,3].group_by(&:reference)

+1. It's sensible (i.e. anyone who knows OOP knows what 'reference' means), there's no overloading of names, and the intention is clear.

So defining tap such that it defaults to a no-op function (i.e. does not yield if block not given) seems perfectly valid to me.

I know I'm throwing a lot of paint at this shed, but while I agree that a default noop #tap is valid, I still strongly believe it makes ary.group_by(&:tap) seem like voodoo. I like #reference a lot.

Updated by Anonymous almost 11 years ago

I think out of all the options proposed, 'identity' is the most readable/quickly understandable.

For example, I think the use of 'identity' reads very nicely in [1,2,3,4].group_by(&:identity)

Updated by phluid61 (Matthew Kerwin) almost 11 years ago

charliesome (Charlie Somerville) wrote:

I think out of all the options proposed, 'identity' is the most readable/quickly understandable.

For example, I think the use of 'identity' reads very nicely in [1,2,3,4].group_by(&:identity)

Except that #identity seems to imply the same thing as #__id__ , and "a".__id__ is not necessarily == "a".__id__ , as Matz said earlier.

The advantage of using #reference is that there's no existing method or concept we're overloading; there are no such things as "reference" objects (or "pointers") in Ruby -- it is understood that all references are automagically dereferenced when operated on -- so returning the references and then comparing them should be understood by most rubyists as effectively the same as comparing the objects directly (whatever "directly" means).

tl;dr:
Defining #identity that conflicts with #__id__ is confusing, however slightly it might be.

Updated by headius (Charles Nutter) almost 11 years ago

phluid61 (Matthew Kerwin) wrote:

charliesome (Charlie Somerville) wrote:

I think out of all the options proposed, 'identity' is the most readable/quickly understandable.

For example, I think the use of 'identity' reads very nicely in [1,2,3,4].group_by(&:identity)

Except that #identity seems to imply the same thing as #__id__ , and "a".__id__ is not necessarily == "a".__id__ , as Matz said earlier.

I have this concern as well. Having "a".__id__/object_id and "a".identity return drastically different things feels like it will just be confusing.

Updated by vjoel (Joel VanderWerf) almost 11 years ago

Another argument against #identity: it is used by several libraries for something completely different. For example, in narray:

>> NMatrix.float(2,2).identity
=> NMatrixfloat2,2: 
[ [ 1.0, 0.0 ], 
  [ 0.0, 1.0 ] ]

It's also used in celluloid-zmq:

s1 = PubSocket.new
s1.identity = "publisher-A"

I vote for "itself" or "self", which are unlikely to be defined anywhere with some fundamentally different meaning.

Updated by marcandre (Marc-Andre Lafortune) over 10 years ago

Slide attached.

I hope to win the prize for simplest slide too.

Updated by Anonymous over 10 years ago

marcandre: I think you made a mistake in your slide. It says "Returns the class of obj", but it should say "Returns obj"

Updated by matz (Yukihiro Matsumoto) over 10 years ago

I can accept #itself. I want to see it isn't conflict with existing methods.

Matz.

Updated by avit (Andrew Vit) about 10 years ago

Rails ActiveSupport includes a similar method called presence. There is also a request to add block support to it, for a similar purpose: https://github.com/rails/rails/pull/13416#issuecomment-32636227

Updated by marcandre (Marc-Andre Lafortune) about 10 years ago

Andrew Vit wrote:

Rails ActiveSupport includes a similar method called presence.

Mmm, no, that's quite different. "".presence # => nil for example.

Updated by fuadksd (Fuad Saud) about 10 years ago

Wouldn’t such method accepting a block remove the need to have Object#tap at all? As I understand this method is just a tap that doesn’t need a block. 
-- 
Fuad Saud
Sent with Airmail

Updated by sawa (Tsuyoshi Sawada) about 10 years ago

I would like to propose receiver as the method name.

Updated by phluid61 (Matthew Kerwin) about 10 years ago

On Jan 21, 2014 12:29 AM, "Fuad Saud" wrote:

Wouldn’t such method accepting a block remove the need to have Object#tap
at all? As I understand this method is just a tap that doesn’t need a
block.

That depends on the contract. I was under the impression that #itself (or
whatever name) in block form would return the value of the block. e.g:

def tap
  yield self if block_given?
  self
end
def itself
  if block_given?
    yield self
  else
    self
  end
end

Updated by fuadksd (Fuad Saud) about 10 years ago

That is interesting behaviour for chaining; not sure if consistent though.


Sent from Mailbox for iPhone

Actions #49

Updated by avit (Andrew Vit) about 10 years ago

Mmm, no, that's quite different. "".presence # => nil for example.

Yes, I was aware of the differences from ActiveSupport presence, I just wanted to point out the similar need for chaining "itself" with a block.

The proposed "itself" method also looks similar to "Enumerable#map" but for a single object, effectively:

["ruby"].map {|n| n.upcase }.first
# same as:
"ruby".itself {|n| n.upcase }

But I suppose "map" as a method name would be out of the question.

Has anyone considered "yield" as the method name? It also seems to fit well, and would likely not conflict with anything:

class Object
  def yield
    if block_given?
      yield self
    else
      self
    end
  end
end

# yield as a noun means "the result": an object's result (its yield) is itself
"ruby".yield  #=> "ruby"

# yield as a verb means "give way to" or "produce": the object gives way to the block
"ruby".yield {|s| s.upcase } #=> "RUBY"

Although there might be confusion between yield as a keyword and self.yield as a method, I do like this symmetry:

yield self         # calls block with self, returns result
self.yield(&block) # calls block with self, returns result
self.yield         # implicit identity, just like: {|obj| obj }

Updated by nobu (Nobuyoshi Nakada) over 9 years ago

  • Description updated (diff)

Yukihiro Matsumoto wrote:

I can accept #itself. I want to see it isn't conflict with existing methods.

It's hard to imagine other functionality from that name for me.
The best way to tell if it will break something should be implementing it before previews, IMHO.

Updated by duerst (Martin Dürst) over 9 years ago

  • Status changed from Feedback to Open

Updated by rafaelfranca (Rafael França) over 9 years ago

We just implemented it on Active Support https://github.com/rails/rails/commit/702ad710b57bef45b081ebf42e6fa70820fdd810

I believe matz already accepted it as #itself so we are renaming it to #itself.

Updated by rafaelfranca (Rafael França) over 9 years ago

Here the implementation. This is my first patch to Ruby so I'm not sure it is correct. Let me know if I need to change something.

Updated by nobu (Nobuyoshi Nakada) over 9 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r47028.


object.c: Object#itsef

  • object.c (rb_obj_itself): new method Object#itsef. based on the
    patch by Rafael França in [ruby-core:64156].
    [EXPERIMENTAL] this method may be renamed due to compatibilities.
    [ruby-core:44704] [Feature #6373]
Actions #55

Updated by laise (Alexey Chernenkov) over 8 years ago

-1

For me it would be better to accept #47 - it improves good old #tap and introduces a new #itself with block.

Copied here:

def tap
  yield self if block_given?
  self
end

def itself
  if block_given?
    yield self
  else
    self
  end
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0