Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Whats even better, though, is not needing 200 lines of code in the first place. The thing I hate about java, is that you're required to use an IDE, or you'll never get anywhere. In Ruby, you just metaprogram in 10 lines what takes 200 in java. Its `attr_accessor :foo, :bar, :baz` in ruby, vs 8 loc for each in Java. Want to change the name? Go change the one word in ruby. No need for an IDE with refactoring support.


Does Java not allow public fields?

The biggest difference there is that Ruby programmers frequently don't think twice about exposing their object's state to anyone and everyone.

It should be one line of code for each attribute in Java "public SomeClass foo;" if we're going for the same semantics as the Ruby example(admittedly, if you don't want to expose that it's a field, that's not quite as easy in Java, although really, there's no reason to not just do this:

  private SomeClass foo_; // I don't know if Java allows methods with the same name as fields.
  public SomeClass foo () { return foo; }
  public SomeClass foo (SomeClass aFoo) { foo = aFoo; }
Yes, that's not what most Java programmers would write, and it's not too concise either, but it's not nearly as bad as you suggest.


Ruby is actually more conservative on this issue, it isn't possible to make fields public. The attr_accessor macro is actually adding getters and setters. The implementions used for the getters and setters are equivalent to those that you would write in java. As mentioned elsewhere you can switch in custom implementations as required but, as in java, the majority of the time the default implementations are sufficient. The difference is that it in ruby you don't need to write the getters and setters until you need the customisation.


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.


You need an IDE in Ruby just as much as in Java. It's the easiest way to browse the code, navigate from place to place, get some auto completion and auto imports, etc...

Of course, Ruby being dynamically typed makes it impossible to have most of the refactorings that statically typed languages take for granted, but that's a separate topic.

Look at it this way: you might think you are productive with Emacs/TextMate/vi, but you would be even more productive with an IDE of the Eclipse or IDEA caliber.

An IDE is nevery mandatory, it just makes you more productive.


"Of course, Ruby being dynamically typed makes it impossible to have most of the refactorings that statically typed languages take for granted, but that's a separate topic."

Most of the refactoring tools that Java IDEs have originated in Smalltalk, an extremely dynamic language.


Most of these refactorings required human intervention, even for simple refactorings like "Rename". When the IDE doesn't have types, some refactorings are simply impossible to perform automatically.

For more details and examples:

http://beust.com/weblog/2006/10/01/dynamic-language-refactor...


The arguments in your linked article are inaccurate. For example: the Refactoring Browser described in "A Refactoring Tool for Smalltalk"(at http://st-www.cs.uiuc.edu/users/droberts/tapos.pdf ), was capable of determining which sends of a renamed message were to the class on which it is to be renamed by analysis of the program's dynamic behavior.

There's of course a limitation on this. To quote the paper: "The major drawback to this style of refac- toring is that the analysis is only as good as your test suite. If there are pieces of code that are not executed, they will never be analyzed, and the refactoring will not be completed for that par- ticular section of code. "


The impracticality of this technique notwithstanding, the article is perfectly accurate based on your own summary: in a dynamically typed languages, automatic refactorings are never 100% safe.


Once you've changed that one word, how do you change all the places that reference it?


sed?


find lib -name '*.pm' | xargs perl -pi -e 's/.../.../'

is usually quite sufficient for purpose if you have a reasonable idea what's going on in your codebase (and if you don't, you probably don't want to be renaming things yet).

Doesn't mean a real refactoring tool such as the ones people've been playing with for http://padre.perlide.org/ wouldn't be better, but it's amazing how well a simple brute force replace works on a reasonably tested codebase.


Might work for classes. Good luck with "count" or "item".

But I take it from your third paragraph that you agree with the OP and myself that IDEs with good refactoring tools are a good thing.


You can always fix it after you get the run time error ;)




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

Search: