On Fri, Oct 26, 2012 at 5:44 PM, Igor Pirnovar <[email protected]> wrote:
> Robert Klemme wrote in post #1081267:
>
>> You are repeating that it is broken but you fail to explain what
>> exactly is broken. That's not a basis for discussions.
>
> I thought my statement "I believe, we all can tolerate this glitch" was
> clear enough. But if you insist to define what is broken, the reply is:
> "Ruby grammar consistency when it comes to mixing classes with Structs".
This has nothing to do with Ruby's grammar. I think I know what
you're up to but the term is simply wrong.
> Every solution that you come up with introduces more complications and
> weird or even unacceptable run-arounds, like your underscore aliasing.
These are basically introduced because you chose to have a property
setter which modifies the value on the fly - this is also a
questionable approach.
> Try using your '_initialize' and then straight 'initialiye' and you'll
?
> create two different behaviours both of whom are wrong. One
> instantiating {{ s = S.new(0) }} with @num to 0, and the other adding 5
> twice making @num 10, when using {{ self.num = n + 5 }} idiom rather
> than {{ @num = n + 5 }}, which Struct does not recognize (this should be
> fixed, namely, Struct should honour '@ semantics'; resorting to
> 'self#var' is not sufficient in all circumstances).
I find that rather foggy. What code are you talking about exactly?
> Struct does not honour Ruby's variable inheritance and class
> initialization grammar with respect to inheritance, i.e.: all subclasses
> have a single set of instance variables in the inheritance hierarchy.
I do not think the thing that you call "initialization grammar"
exists. Inherit from Hash and Array and you won't see instance
variables either. Actually, all classes which are implemented in C
(which includes std lib as well as extensions) do have the liberty to
store the state in any way they like. Generally using accessors to
modify state is a safer method. It just happens that in most user
written classes the direct access to instance variables works and
gives expected results.
> If
> the idiom {{ class A < Struct.new(:num); end }} makes Struct a
> superclass of A,
It doesn't - at least not directly. Struct.new creates a new class
which sits between them.
irb(main):002:0> class A < Struct.new(:num); end
=> nil
irb(main):003:0> A.ancestors
=> [A, #<Class:0x8b37678>, Struct, Enumerable, Object, Kernel, BasicObject]
> then class A and indeed all its subclasses should
> inherit @num instance method from Struct.
First of all @num is not a method. This is an instance variable read access.
The method does not exist in Struct - and it can't for obvious reasons.
irb(main):005:0> Struct.instance_method :num
NameError: undefined method `num' for class `Struct'
from (irb):5:in `instance_method'
from (irb):5
from /usr/local/bin/irb19:12:in `<main>'
Instead it's defined in the anonymous superclass of A:
irb(main):006:0> A.instance_method :num
=> #<UnboundMethod: A(#<Class:0x8b37678>)#num>
irb(main):007:0> A.instance_method(:num).owner
=> #<Class:0x8b37678>
I am starting to wonder whether you understand how Struct works.
> Accessing Struct's @num via {{
> self.num }} works only when you are using straight assignment, however
> if you need to invoke any kind of computation, you have to resort to
> tricks like aliasing which works only sometimes.
>
> S = Struct.new :num do
> alias _initialize initialize
> # def _initialize(n) #=> @num==0
> def initialize(n) #=> @num==10
???
> super
> self.num = n + 5
> end
>
> alias _num= num=
> def num=(n) self._num= n + 5; end
> end
>
> s = S.new 0
> p s.num #=> 10; ## with: '_initialize' #=>0
It's obvious that you get wrong values if you create flawed logic.
This is also not what I had suggested.
> s.num = 100
> p s.num #=> 105
>
> The trouble with Struct is that there is no way to implement
> initialization of instance variables in base class (ie. in Struct) that
> require more elaborate initialization skims than straight assignment.
> You can accomplish this only with regular classes and their inheritance
> hierarchies!
That is not true. If you only want to modify values during
initialization you can always do
S = Struct.new :a, :b do
def initialize(a, b)
self.a = a * 33
self.b = b / 10
end
end
irb(main):026:0> x = S.new 100, 200
=> #<struct S a=3300, b=20>
irb(main):027:0> x.a
=> 3300
irb(main):028:0> x.b
=> 20
You even can omit the super invocation.
> When you have to resort to tricks to accomplish things that are not out
> of the ordinary, you better avoid those features when working outside of
> your quick and dirty domain or "research lab", and Struct certainly
> qualifies for that!
That's not a dirty trick - it's just a slightly inconvenient way to
use Struct because one cannot use #initialize as predefined. Other
than that this is what you would for a regular class as well. But you
still benefit from properly defined #eql?, #hash, #[] etc. You're
simply not using the default constructor but still gain useful
functionality. Heck, it doesn't even involve meta programming. For
me this does not qualify as hack or trickery.
Cheers
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
-- You received this message because you are subscribed to the Google Groups
ruby-talk-google group. To post to this group, send email to
[email protected]. To unsubscribe from this group, send email
to [email protected]. For more options, visit this
group at https://groups.google.com/d/forum/ruby-talk-google?hl=en