3 ms·
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 an
by ekiru 16y ago
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.
- flomo 16y agoThe difference is that in Ruby you can add getter/setter methods at a later date without changing the interface.
- ekiru 16y agoI 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.
- jamesbritt 16y ago" 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. )
- ekiru 16y agoIf 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)); }
- jamesbritt 16y ago"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.
- ollysb 16y agoRuby 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.