Code documentation question about AF and RI (Java)

JoLLyRoGer

Diamond Member
Aug 24, 2000
4,153
4
81
So this has to do with homework... I'll just put that out there up front.

AF and RI; For the most part I understand what they are, why they exist, and to a lesser extent how to implement them but what about when it comes to instance variables?

Should AF and RI also address instance variables contained within a method? And if so, where in the body of the code should this information appear?

I typically place AF and RI right after local variable declarations while implementing the repOK() just before the constructor and overriding toString() for AF (where feasible).

What is the correct format (or Industry practice) for capturing instance variables with AF (if it's even done at all) and second to that, how would you even check them with repOK(); <==Or did this just answer my own question?

Thanks guys (and gals)
-JR
 

slugg

Diamond Member
Feb 17, 2002
4,723
80
91
I have been coding in Java for 16 years and have a degree in computer science, yet I still had no idea what you were asking. So I Googled it. Turns out that a lot of this terminology is only used in some specific academic literature. The rest of the industry does not talk like this.

Before I can give you any answer that makes sense, I need to lay a bit of a foundation. Bare with me.

AF = abstract function, I believe. Java does not have abstract functions; it has abstract classes and abstract methods. Abstract methods are abstract function-members of an abstract class.

RI = representation invariance. In the real world, this doesn't really exist. The closest thing to it is a concept called immutability - the ability for an object/variable to prevent or disallow mutations to its state. The most sensible way to implement this in Java is to declare instance variables (computer science term is "data members") with the "final" keyword, assign them a value in your constructor, and only implement an accesor function ("getter" in Java terms).

Now, on to your first question and following up on your comment. You asked and said:

Should AF and RI also address instance variables contained within a method? And if so, where in the body of the code should this information appear?

I typically place AF and RI right after local variable declarations while implementing the repOK() just before the constructor and overriding toString() for AF (where feasible).

So there's a fundamental problem with that question, and thus, it cannot be answered. Instance variables are not contained within a method; those are called local variables. Even if that were somehow true, Java does not have Abstract Functions (see what I said about that), nor does it have any kind of representation invariance features, other than implementing an object without any mutation capability.

As far as your comment about what you typically do, if you review the foundational knowledge I just explained, you'd understand why your comment is confusing. I honestly have no idea what you tried to say. And repOK() does not exist or make any sense in the real world. You can make immutable objects and use validators in the real world, but I still don't even know if that satisfies what your homework is trying to get you to do.

As far as your final question, I believe everything I've said so far covers it. Please do ask as many questions as you need; that book or class of yours seem very far from reality.

Good luck :)
 
Last edited:
  • Like
Reactions: JoLLyRoGer

JoLLyRoGer

Diamond Member
Aug 24, 2000
4,153
4
81
I have been coding in Java for 16 years and have a degree in computer science, yet I still had no idea what you were asking. So I Googled it. Turns out that a lot of this terminology is only used in some specific academic literature. The rest of the industry does not talk like this.

Before I can give you any answer that makes sense, I need to lay a bit of a foundation. Bare with me.

AF = abstract function, I believe. Java does not have abstract functions; it has abstract classes and abstract methods. Abstract methods are abstract function-members of an abstract class.

RI = representation invariance. In the real world, this doesn't really exist. The closest thing to it is a concept called immutability - the ability for an object/variable to prevent or disallow mutations to its state. The most sensible way to implement this in Java is to declare instance variables (computer science term is "data members") with the "final" keyword, assign them a value in your constructor, and only implement an accesor function ("getter" in Java terms).

Now, on to your first question and following up on your comment. You asked and said:



So there's a fundamental problem with that question, and thus, it cannot be answered. Instance variables are not contained within a method; those are called local variables. Even if that were somehow true, Java does not have Abstract Functions (see what I said about that), nor does it have any kind of representation invariance features, other than implementing an object without any mutation capability.

As far as your comment about what you typically do, if you review the foundational knowledge I just explained, you'd understand why your comment is confusing. I honestly have no idea what you tried to say. And repOK() does not exist or make any sense in the real world. You can make immutable objects and use validators in the real world, but I still don't even know if that satisfies what your homework is trying to get you to do.

As far as your final question, I believe everything I've said so far covers it. Please do ask as many questions as you need; that book or class of yours seem very far from reality.

Good luck :)

Thanks for your response and I have no problems with anything you've just explained. Perhaps what I'm contending with here is specific to just this class I am in. (It's a software design class) A lot of this stuff is conceptually new to me as well. I've done some Java programming in the past myself and I can completely understand why I came across as confusing. It confuses me as well.

I'll try my best to fill in the gaps to the best of my understanding. My apologies for not providing more context and just ass-u-me-ing that this stuff was common knowledge among professional programmers.

AF, as it is being taught to me is the Abstraction Function. Not an Abstract Function (Which I would also immediately associate with an abstract method.)
The best I can tell, it is a block of comments that summarily explain the purpose of each data member.

RI, as it is being taught, is how we apply constraints to the data members. Such as checking to make sure a variable contains a certain value before proceeding. If I have it right, it's a layer of error checking essentially. I can see what they're getting at, but for me I think it would be easier just to handle this stuff right in the individual methods. But hey, not my rules and I probably write pretty sloppy code at best. Either way, RI becomes the blueprint for repOK()

Let me provide some pseudo-code to back this up. First up so you have some background info, is they have us doing a 'specification' class which contains all the methods of a class but contain only comments detailing its intended functionality. It is up to the programmer to implement the methods.

This is the specification for the class 'Card' from a classic Hi-Low guessing game example.

The question in the homework was to Specify the Card type (part of the posted HighLow Java program). Give the rep invariant and abstraction function. Implement the repOk method.

Code:
public class Card {
    //OVERVIEW: An object of type Card represents a playing card from a
    //   standard Poker deck, including Jokers.  The card has a suit, which
    //   can be spades, hearts, diamonds, clubs, or joker.  A space, heart,
    //   diamond, or club has one of the 13 values: ace, 2, 3, 4, 5, 6, 7,
    //   8, 9, 10, jack, queen, or king.  Note that "Ace" is considered to be
    //   the smallest value.  A joker can also have an associated value;
    //   this value can be anything and can be used to keep track of several
    //   different jokers.
  
    public Card(){
        //Overview: Constructor takes no parameter; the default constructor
        //Requires: nil
        //Modifies: this
        //Effect:  Initializes a Card object where suit type is JOKER and the
        //  associated value == 1.
    }
    public Card(int theValue, int theSuit) {
        //Overview: Creates a card with a specified suit and value.
        //Requires: theValue must be in the range of 1 through 13 and
        //  theSuit must be in the range of 0 to 4 unless theSuit == JOKER.
        //  If theSuit == JOKER; then theValue must be >= 1.
        //Modifies: this
        //Effects: Evaluates theValue and theSuit. Compare to permissible range.
        //  If theValue and theSuit are permissible create Card object.
        //  Otherwise throw an illegal suit or illegal value exception.
        //  Initialize constants; 'value' == theValue and 'suit' == theSuit.
    }
  
    public int getSuit() {
        //Overview: Return the card suit equal to one of the constants
        //  Card.SPADES, Card.HEARTS, Card.DIAMONDS, Card.CLUBS, or Card.JOKER
        //Requires: nil
        //Modifies: nil
        //Effects: Returns the value for 'suit' element.
    }
  
    public int getValue() {
        //Overview: Return the value of the Card.  1 - 13 for regular cards
        //  or any value >= 1 for a Joker
        //Requires: nil
        //Modifies: nil
        //Effects: Returns the value for 'value' element.
    }
  
    public String getSuitAsString() {
        //Overview: Returns string representation of a Card's suit
        //Requires: value of suit between 0 to 4;
        //Modifies: nil
        //Effects: Switch case compares value of suit to a set of constants
        //  and returns with a corresponding String representing the suit
        //  "Spades", "Hearts", "Diamonds", "Clubs", "Joker"
    }
              
    public String getValueAsString() {
        //Overview: Returns a string representation of a Card's value
        //Requires: 'suit' and 'value' where 'value' must be in the range of
        //  1 to 13;
        //Modifies: nil
        //Effects: If 'suit' == JOKER; return 'value' as a String.
        //  If suit is HEARTS, CLUBS, DIAMONDS, SPADES, evaluate 'value' and
        //  return the appropriate representation as a String
        //  where values, 1, and values 11-13 correspond to "Ace", "Jack",
        //  "Queen", and "King" respectively.
    }
  
    public String toString(){
        //Overview: Returns a string representation of this card including
        //  suit and value (a Joker with value 1 returns as just "Joker")
        //Requires: 'suit' and 'value' but not as parameters
        //Modifies: nil
        //Effects:  Evaluates suit and value and returns a String of
        //  "Suit of Value" by calling getValueAsString() and getSuitAsString()
        //  If suit == JOKER && value == 1; return "Joker" or
        //  If suit == JOKER && value == 'some_number';
        //      return "Joker #'some_number'.
    }
}// end class

This next snippet is the AF, RI, and repOK()

Code:
   //AF: SPADES, HEARTS, DIAMONDS, CLUBS and JOKER = constant int codes
   //    for the 4 suits plus Joker;
   //  ACE, JACK, QUEEN, KING = constant int codes for the non-numeric cards.
   //    Cards 2 through 10 have their numerical values for their codes;
   //  'suit' refers to the card's suit, one of the constants SPADES, HEARTS
   //    DIAMONDS, CLUBS, or JOKER.  The suit cannot be changed after the
   //    card is constructed.;
   //  'value' refers to the card's value.  For normal cards the value
   //    will be 1-13 where 1 is represented by the constant ACE and
   //    non-number cards 11-13 are represented by constants JACK, QUEEN,
   //    and KING respectively.  The value of 'value' cannot be changed
   //    after the card is constructed.
 
   //RI: Calls to constructor(s) must pass either NO parameters or
   //    must pass BOTH theValue and theSuite as integers;
   //  Default constructor accepts no values and will create a card
   //    "JOKER" and initialize ‘value’ to '1'.
   //  For second constructor method; integer values for theValue and
   //    theSuit are required where:
   //    ((theValue >=1)&&(theValue <=13))&&((theSuite >=0)&&(theSuite <=4));
   //  If (suit == JOKER); theValue can be any value >=1;

   //RI Implementation
       public boolean repOK(){
       if ((suit != JOKER) && ((suit >=0)&&(suit <=4)) &&
          ((value >=1)&&(value <=13))) {
            return true;
       } else if ((suit == JOKER)&&(value >=1)){
           return true;
       } else{   
       return false;
       }
   }


Hopefully this helps?

Thanks again!
-JR
 

slugg

Diamond Member
Feb 17, 2002
4,723
80
91
Oh man. Where do I begin... there's just so much to type and I'm just on my phone.

Let me first tell you just how sorry I am that you're taking this class. The pseudo-code they gave you is just plain terrible and wrong. If you code like this, or function like this in any way with real code, you will fail. So whatever you do, keep in mind that you're doing this just to pass this class, not because it's valuable. At the end of this class, pretty my forget everything. That's my biggest advice to you. I know I sound very negative, but I really am trying to help, and it's the truth.

Alright... so it sounds like they just want you to replace the comments with code that does what the comments say.

For AF/Abstraction-Function (which, by the way, makes NO SENSE because it's not abstracting anything and it's not a function, nor does it serve a function).... it says that neither the suit nor the value may be changed after the Card is constructed. So let's get those constructors working.

Declare two instance variables (also known as data members): final int suit, and final int value. Now in the constructor that has two parameters, set both of the instance variables to the values passed in as the two parameters. After that (still inside of the constructor), call repOK(); if it returns false, throw an exception (or whatever your homework wants you to do).

The second constructor, the one without any arguments, is easy. All you need to do is call the other constructor from this one, passing in the default suit and value that your homework told you about. Google "constructor chaining".

And this point, getValue() and getSuit() should be obvious.

The homework did tell you exactly how it wants you to declare the suits and face cards (integer constants). In this case, they will be static, since they will belong to the Card class, as opposed to an instance of the class. Since they are constants, they should also be declared as final.

Do you need me to explain the get*AsString() methods?

Anyway... what you should take away from this, but is not how they're teaching it, is that you've made an immutable object. Once you create a Card object, it will never change. Additionally, your Card object guarantees that it will always be in a valid state, since its state cannot change (immutable) and its state is validated upon construction.
 
Last edited: