[Newbie] Immutable objects

Discussion in 'Ruby' started by Einar Høst, Mar 9, 2006.

  1. Einar Høst

    Einar Høst Guest

    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
    Einar Høst, Mar 9, 2006
    #1
    1. Advertising

  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
    Robert Klemme, Mar 9, 2006
    #2
    1. Advertising

  3. On Mar 9, 2006, at 6:23 AM, Einar H=F8st wrote:

    > Hi,
    >
    > Still working on the basics... for my card game, I want the Card =20
    > objects to be immutable. Is it sufficient to put 'freeze' in the =20
    > end of the constructor, like this (suit and rank will be strings):
    >
    > def initialize(suit, rank)
    > @suit, @rank =3D suit, rank
    > freeze
    > end


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

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

    James Edward Gray II=
    James Edward Gray II, Mar 9, 2006
    #3
  4. Einar Høst

    Einar Guest

    Robert Klemme wrote:
    > Einar Høst wrote:
    >
    >
    > 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
    >


    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 :)

    Thanks!

    - Einar
    Einar, Mar 9, 2006
    #4
  5. Einar Høst

    Einar Guest

    James Edward Gray II wrote:
    > On Mar 9, 2006, at 6:23 AM, Einar Høst wrote:
    >
    > 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 Gray 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
    Einar, Mar 9, 2006
    #5
  6. Einar Høst

    George Ogata Guest

    Einar <> writes:

    > Robert Klemme wrote:
    >> Einar Høst wrote:
    >> 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
    >>

    >
    > 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 :)


    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.
    George Ogata, Mar 9, 2006
    #6
  7. Einar Høst

    Einar Guest

    George Ogata wrote:
    > Einar <> writes:
    >
    >
    >>Robert Klemme wrote:
    >>
    >>>Einar Høst wrote:
    >>>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
    >>>

    >>
    >>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 :)

    >
    >
    > 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.


    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
    Einar, Mar 10, 2006
    #7
  8. 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. :)

    Kind regards

    robert
    Robert Klemme, Mar 10, 2006
    #8
  9. Einar Høst

    Einar Høst Guest

    Robert Klemme wrote:
    > Einar wrote:
    >
    >>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. :)
    >


    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) :)

    - Einar
    Einar Høst, Mar 10, 2006
    #9
  10. Einar Høst wrote:
    > Robert Klemme wrote:
    >> Einar wrote:
    >>
    >>> 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. :)
    >>

    >
    > 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)
    > :)


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

    robert
    Robert Klemme, Mar 10, 2006
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Esko
    Replies:
    2
    Views:
    313
    Thomas G. Marshall
    Oct 6, 2005
  2. Replies:
    2
    Views:
    365
    John Roth
    Apr 15, 2004
  3. 7stud
    Replies:
    11
    Views:
    662
    Dennis Lee Bieber
    Mar 20, 2007
  4. Mize-ze
    Replies:
    2
    Views:
    325
    Hendrik Maryns
    Apr 2, 2007
  5. Sam Kong
    Replies:
    3
    Views:
    121
    Sam Kong
    Apr 8, 2006
Loading...

Share This Page