Hacker News new | past | comments | ask | show | jobs | submit login

The difference is that in Ruby you can add getter/setter methods at a later date without changing the interface.



I know. That's why I include the admittedly a bit longer and boiler-plate-y-er code sample. Same effect as the ruby. Unfortunately, 3 lines per attribute. A bit more explicit and quicker to change when you make the getter/setter methods actually do something.

I prefer the Ruby. But, frankly, Ruby has too much boilerplate for attributes, too. I have to explicitly add attribute handling code in initialize? Why?

No, thanks, I'll use Perl 6:

  has $.foo is rw;
There you go. An lvalue accessor method for an attribute, and the ability to set it in the constructor with the named argument ":foo(someValue)". And, if I want to add a type constraint, it's a simple matter of doing this instead:

  has Int $.foo is rw;
Or even this if I only want even numbers:

  has Int $.foo where { $_ % 2 } is rw;
If I really want to, I can manually implement my own constructor, but often, I won't need to.

If I want the attribute to be private, I just replace "$.foo" with "$!foo" and it's only accessible within the class.

CLOS also makes this very simple, you just add an entry in the slots list of the class like so:

(foo :accessor foo :initarg :foo)

You can also do type-checking by adding ":type some-type-specifier", specify that it's either a class or instance(the default) slot with ":allocation class" or ":allocation instance", use :reader or :writer instead of :accessor to only generate a reader or a writer accessor or :initform to give the slot a default value.

Ruby is at a nice place on the accessor definition boilerplate continuum, but it's nowhere near the bottom.


" I have to explicitly add attribute handling code in initialize? Why?"

'Attributes' are just methods like any other. What code do you think you need in initialize?

(Encouraging people to think of some methods as 'attributes' was a mistake, but also now a long-lost battle. It breaks the concept of the "messages only" Ruby object model, even though that's exactly what's happening. )


If I want them to be initialized when .new is called, I need explicit code in initialize. Yes, it the attributes are externally mutable, one can set them after initialization, but sometimes you don't want an externally mutable attribute.

Suppose I have this class(if it doesn't exactly work, sorry, I'm not fluent in Ruby):

  class Complex
      attr_accessor :re, :im

      def initialize(aRe, anIm)
          re = aRe
          im = anIm
      end
  end
In Perl 6, I get almost the same thing(with explicit attributes as if I had done "def initialize( initargs ); re = initargs[:re]; im = initargs[:im];end" for the initialize method) with this:

  class Complex {
     has ($.re is rw, $.im is rw);
  }
If I want to do as in the actual Ruby example, I just add this:

  method new ($aRe, $anIm) {
    self.bless(*, :re($aRe), :im($anIm));
  }


"If I want them to be initialized when .new is called, I need explicit code in initialize."

Sure, but that's true of all instance variables in Ruby. That there is a method of the same name as an instance variable is an implement choice; it shouldn't make things magical. (I don't like the idea that a public API reveals the implementation, so I don't like to encourage this automagic tying of method names and instance variables. But clearly many like to think of Ruby as a language with "public properties", perhaps because of wanting it to be like other languages they are more used to.)

If you want smarter attribute accessor code, perhaps fattr would help:

  http://github.com/ahoward/fattr

" but sometimes you don't want an externally mutable attribute."

This is my point. Why would you think of Ruby as having "externally mutable attributes"? There is private data (instance vars) and code to respond to messages, which may or not alter instance data. No data are public by default (barring the usual metaprogramming hooks to get around that). But an idiom was promoted to encourage people to think of a coincidence of method name and instance var name as being "attributes". Later, people have to unlearn stuff in order to properly grok how Ruby works.


It seems I need to clarify something.

When I refer to an externally mutable attribute, I am not making any statements about the details of the storage or interface of the "attribute". I am referring to any bit of information that can be retrieved somehow and modified somehow. That might be implemented by performing some operation on some other attribute, it might be an actual physical instance variable, it might just be a variable closed over by the accessors, it might be something else. What matters is that objects of the class present some kind of interface that allows setting a value for it and retrieving a previously set value.

With that said, on the main body of my reply:

"Sure, but that's true of all instance variables in Ruby."

Right. The question is: should that necessarily be the case? If you're going to have a way to auto-generate methods that provide an externally mutable attribute(see above for working definition of this term) as Ruby does, why not provide at least the option of auto-generating the constructor that sets those attributes, with the option of overriding that if you don't want that behavior?

'Why would you think of Ruby as having "externally mutable attributes"?' Languages don't have "externally mutable attributes", particular interfaces within those languages do. Any Ruby class which uses attr_accessor does. Similarly, any Perl 6 class that contains "has $.foo is rw" and doesn't override the generated foo methods does. Similarly, any Java class with either a public field or a private field with corresponding getFoo and setFoo methods does.

"There is private data (instance vars) and code to respond to messages, which may or not alter instance data."

The private data is part of the implementation. The implementation is not part of what I call "externally mutable attributes". The messages may or not alter instance data, but whether they modify instance data is not part of the interface of an externally mutable attribute either. An externally mutable attribute could look up a page on a website, and send a POST request to modify it upon setting. That's a bad idea when that's not the express purpose of the attribute, but it's one way of implementing externally mutable attributes that doesn't have to modify any instance data.

"No data are public by default (barring the usual metaprogramming hooks to get around that)."

If you use attr_accessor, then yes, there is some public data. Given that I was responding to a post about comparing the Ruby way to create an instance variable and read and write accessors to the Java way, it makes sense to compare the Ruby way to other languages, no? By the way, if you don't like data defaulting to public(me, either), you might be happy to know that Perl 6 has an equally convenient way of creating private attributes(they're not even available to subclasses): just replace "$.foo" with "$!foo".

'But an idiom was promoted to encourage people to think of a coincidence of method name and instance var name as being "attributes".' I agree that an instance-var named @foo and accessor methods named foo and foo= do not necessarily comprise an externally mutable attribute "foo". However, two methods foo and foo= or setfoo or whatever you want do, if the foo= method is specified as determining what all future calls of foo before another foo= call returns. foo doesn't even have to return the exact value given to foo=. Its result just has to be determined by the call to foo=.

I suspect our disagreement is largely an artifact of differing definitions. If that's the case, I'm sorry for not sooner clarifying my definition for "externally mutable attribute".


'If you use attr_accessor, then yes, there is some public data ...I suspect our disagreement is largely an artifact of differing definitions. If that's the case, I'm sorry for not sooner clarifying my definition for "externally mutable attribute".'

Seems to be the case. Using attr_accessor is no different than defining methods by hand that just happen to have the same name as an instance variable. By one view, having any message that returns a value means the object has public data. I think that's your POV. Still, I think few other people think of all such methods as attributes or accessors; this may be my own skewed view of what I've seen among Rubyists.

I think the attr_* methods grew out of early Rubyists finding themselves writing the same sort of code and decidinf to automate that with some metaprogamming. I don't know why they don't include a means to also set a defaut value, but then fattr may just be a continuation of that process: Use the language to extend the language.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: