# Defining struct in a class

**URL:** <https://www.ruby-forum.com/t/defining-struct-in-a-class/189800>\
**Category:** Ruby\
**Created:** [June 8, 2010, 12:16am UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800 "2010-06-08T00:16:30Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 8, 2010, 12:16am UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/1 "2010-06-08T00:16:30Z")

</div>

How can I properly define a struct in a class?

If I have

class Cards  
Card = Struct.new(:suit, :number)  
@cardsOnHand=[]

```
@cardsOnHand.push(Card.new("S","5"))

```

end

This will give me an error message saying the push is not defined for  
NilClass. How should I fix this?

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 8, 2010, 1:05am UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/2 "2010-06-08T01:05:41Z")

</div>

On 2010-06-07 15:16:33 -0700, William Song said:

> This will give me an error message saying the push is not defined for  
> NilClass. How should I fix this?

The error you reported has nothing to do with your Card struct. Besides  
which, your code works for me as is.

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 8, 2010, 1:16am UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/3 "2010-06-08T01:16:54Z")

</div>

Rein H. wrote:

> On 2010-06-07 15:16:33 -0700, William Song said:
> 
> > This will give me an error message saying the push is not defined for  
> > NilClass. How should I fix this?
> 
> The error you reported has nothing to do with your Card struct. Besides  
> which, your code works for me as is.

Sorry, I meant to put it into a function. I over-simplified it when  
posted here.

class Cards  
Card = Struct.new(:suit, :number)  
@cardsOnHand=[]

```
def a()
    @cardsOnHand.push(Card.new("S","5"))
end

```

end

cards = Cards.new  
cards.a()

The above code will give an error.

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 8, 2010, 7:00pm UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/4 "2010-06-08T19:00:37Z")

</div>

I assume you want the first two lines of you class definition to be run  
every time someone creates an instance of you class. If you do you  
should put the into a method called initialize. That will be run  
automatically when new is called and should solve your problem

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 8, 2010, 6:55am UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/5 "2010-06-08T06:55:43Z")

</div>

On 2010-06-07 16:16:57 -0700, William Song said:

> Sorry, I meant to put it into a function. I over-simplified it when
> 
> cards = Cards.new  
> cards.a()
> 
> The above code will give an error.

You create an instance variable, @cardsOnHand, in the class scope. That  
means it is an instance variable of the object Cards (the class). You  
then attempt to access it in the scope of an instance method, i.e. on a  
Cards instance. They are two different objects, two different scopes  
and two different variables.

I would suggest reading the chapter Classes, Objects and Variables in  
[Programming Ruby: The Pragmatic Programmer's Guide](http://ruby-doc.org/docs/ProgrammingRuby) to better understand the  
concept of scope in Ruby and how it effects variables. Hint: you  
probably want to set this instance variable when you _initialize_ an  
Cards object.

I would also suggest reading  
[styleguide/RUBY-STYLE at master · leahneukirchen/styleguide · GitHub](http://github.com/chneukirchen/styleguide/blob/master/RUBY-STYLE) to get  
a better grasp of common Ruby style, such as two space indention,  
adding spacing before and after the = in a variable assignment, using  
camel\_case for variable and method names, and removing empty () on the  
ends of methods.

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 9, 2010, 4:04pm UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/6 "2010-06-09T16:04:26Z")

</div>

----- “William Song” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ## This will give me an error message saying the push is not defined for NilClass. How should I fix this?
> 
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

Your problem is not a struct but the fact that you are not properly  
instantiating an instance variable. I probably wouldn’t use a struct  
like you have instead solve the problem understand that your cards class  
is a deck that structurally is just an array:

class Deck \< Array  
def add( card )  
raise ArgumentError unless card.is\_a?( Card )  
# Other checks on how many cards per suite and not allowing  
duplicate cards

```
self.push( card )

```

end  
end

class Card  
attr\_accessor :number, :suite

def initialize( number, suite )  
@number = number.to\_s if /[2-9AKQJ]/.match( number.to\_s )  
@suite = suite.to\_s if /[CHDS]/.match( suite.to\_s )

```
raise Exception if @number.nil? || @suite.nil?

```

end  
end

deck = Deck.new

deck.add( Card.new( 3, :H ) )  
deck.add( Card.new( ‘4’, ‘S’ ) )

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 9, 2010, 6:37pm UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/7 "2010-06-09T18:37:49Z")

</div>

----- “Rein H.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > @cardsOnHand=[]  
> > > instantiating an instance variable. I probably wouldn’t use a struct  
> > > end  
> > > end  
> > > deck of cards. It would be better to create a Deck class that delegated  
> > > –  
> > > Rein H.  
> > > [http://puppetlabs.com](http://puppetlabs.com)  
> > > [http://reinh.com](http://reinh.com)

Thanks for pointing that out Rein. You learn something new every day  
when active in this mailing list. Forwardable might be possible but I  
think you are right that Deck is really its own class that uses an array  
object as the internal data store.

---

<div class="post-metadata">

**Author:** ![wfspoet](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/e480ec/32.png) [@wfspoet](https://www.ruby-forum.com/u/wfspoet)\
**Post date:** [June 9, 2010, 6:20pm UTC](https://www.ruby-forum.com/t/defining-struct-in-a-class/189800/8 "2010-06-09T18:20:50Z")

</div>

On 2010-06-08 14:02:03 -0700, Wes B. said:

> > @cardsOnHand.push(Card.new(“S”,“5”))  
> > class is a deck that structurally is just an array:  
> > class Card  
> > deck = Deck.new
> 
> deck.add( Card.new( 3, :H ) )  
> deck.add( Card.new( ‘4’, ‘S’ ) )

The fact that the Deck class violates the Liskov Substitution Principle  
should imply that a Deck is not necessarily an Array. For instance, the  
semantics of many Array and Enumerable methods would be undefined on a  
deck of cards. It would be better to create a Deck class that delegated  
semantically appropriate methods to an internal array object (using  
Forwardable, for instance) rather than expecting a Deck to conform to  
the entire Array interface.

This is why it is, in general, somewhat dubious to subclass base  
classes for your own use, even when there seems to be a superficial  
similarity.

Of course, none of this has anything to do with the original problem.
