Immutable objects


#1

Hi,

Still working on the basics… for my card game, I want the Card objects
to be immutable. Is it sufficient to put ‘freeze’ in the end of the
constructor, like this (suit and rank will be strings):

def initialize(suit, rank)
@suit, @rank = suit, rank
freeze
end

Thanks,
Einar


#2

Einar Høst wrote:

Hi,

Still working on the basics… for my card game, I want the Card
objects to be immutable. Is it sufficient to put ‘freeze’ in the end
of the constructor, like this (suit and rank will be strings):

def initialize(suit, rank)
@suit, @rank = suit, rank
freeze
end

It’s not sufficient, you’ll have to freeze those strings, too. Note
that
this will freeze the originals which probably is a bad idea. You could
do

def ini(suit, rank)
@suit = suit.dup.freeze
@rank = rank.dup.freeze
freeze
end

In practice I believe it’s rarely seen that people actually use freeze.

HTH

robert

#3

On Mar 9, 2006, at 6:23 AM, Einar Høst wrote:

Hi,

Still working on the basics… for my card game, I want the Card
objects to be immutable. Is it sufficient to put ‘freeze’ in the
end of the constructor, like this (suit and rank will be strings):

def initialize(suit, rank)
@suit, @rank = suit, rank
freeze
end

As a Ruby rule of thumb, you make an immutable object just by
providing no methods to change the instance data.

Technically, there are ways around that, but there are also ways
around freeze() . Don’t lose a lot of sleep over these though. If
people don’t follow your API, they know they are breaking the rules
and they are responsible for the consequences.

James Edward G. II


#4

James Edward G. II wrote:

James Edward G. II

Thanks - that answers my real question, ‘how do you make an object
immutable in Ruby’. It’s not at all important in this app, which is just
a hobby project for my own amusement and education.

  • Einar

#5

Einar removed_email_address@domain.invalid writes:

Ah, I see - in C# “where I come from”, strings are immutable. Of
course, no-one will be using this code except me, so I’m definitely
conjuring imaginary problems here - but at the same time, the whole
point of this project is to learn about the language :slight_smile:

For things like @suit – which I take it can only take one of four
enumerated values – I think it’s actually more rubyesque to use
symbols. e.g.:

@suit = :spade

This has the side benefit that Symbols themselves are effectively
immutable.

But as Robert and James hinted, freezing is seldom used. It’s like
type-checking: you can be a complete nazi about banning anything out
of line, but (a) you lose elegance and simplicity of code and (b) your
tests should probably be checking this anyway. YMMV.


#6

Robert K. wrote:

end

Ah, I see - in C# “where I come from”, strings are immutable. Of course,
no-one will be using this code except me, so I’m definitely conjuring
imaginary problems here - but at the same time, the whole point of this
project is to learn about the language :slight_smile:

Thanks!

  • Einar

#7

George O. wrote:

@suit = suit.dup.freeze

type-checking: you can be a complete nazi about banning anything out
of line, but (a) you lose elegance and simplicity of code and (b) your
tests should probably be checking this anyway. YMMV.

Thanks - this is starting to feel like playing an adventure game where
the map of the terrain becomes visible as I explore it (or rather: as
you tell me about it). It looks like symbols are appropriate here. I’m
thinking the same might be the case for rank (e.g. “card value” from 2
up to ace). It might look weird for the numeric values (e.g. :2 or :3 -
which might not even be legal? but then :two and :three would), but not
so for e.g. :jack or :queen.

I’m a bit ambivalent on the strictness issue. I buy your arguments for
a) simplicity and b) testing over typing (Bruce Eckel wrote an article
on that, which made a lot of sense to me). At the same time, I’m still
carrying scars from having a few leaks in the abstractions for a data
access API I wrote in my previous job…

  • Einar

#8

Robert K. wrote:

Ah, yes, I guess it’s like physical exercise - “no pain, no gain”
(suddenly, images of Gwydion from King’s Quest III appear in my head)
:slight_smile:

  • Einar

#9

Einar wrote:

Thanks - this is starting to feel like playing an adventure game where
the map of the terrain becomes visible as I explore it (or rather: as
you tell me about it). It looks like symbols are appropriate here. I’m
thinking the same might be the case for rank (e.g. “card value” from 2
up to ace). It might look weird for the numeric values (e.g. :2 or :3

  • which might not even be legal? but then :two and :three would), but
    not so for e.g. :jack or :queen.

Alternatively you could use constants

module Deck
JACK = “jack”.freeze
QUEEN = “queen”.freeze

end

But IMHO symbols are more elegant here. OTOH you can define a
specialized
class for this which also holds numeric values

module Deck
CARD = Struct.new :name, :value

def self.card(name, val)
CARD.new(name.freeze,val).freeze
end

QUEEN = card “queen”, 10
JACK = card “jack”, 11
ACE = card “ace”, 100

end

I’m a bit ambivalent on the strictness issue. I buy your arguments for
a) simplicity and b) testing over typing (Bruce Eckel wrote an article
on that, which made a lot of sense to me). At the same time, I’m still
carrying scars from having a few leaks in the abstractions for a data
access API I wrote in my previous job…

But these are the things that make us learn. :slight_smile:

Kind regards

robert

#10

Einar Høst wrote:

But these are the things that make us learn. :slight_smile:

Ah, yes, I guess it’s like physical exercise - “no pain, no gain”
(suddenly, images of Gwydion from King’s Quest III appear in my head)
:slight_smile:

Actually I believe this is how learning works: basically it’s trial and
error. If you run into an error, you usually learn something. :slight_smile:

robert