What does 'returns an instance' mean ?

Hi,

I'm working my way through a book on Arduino programming and I'm kind of stuck at a bit about IF loops. The code is for writing data to an SD card, and there is a line earlier on that says 'File file;'. I'm guessing the command 'File' is a function of the SD.h library ? But what does that command do ? The book skims over it.

Later on, there is an IF loop that starts with;

file = SD.open("data.txt", FILE_WRITE);
if (file) {
while (millis() < (runningTime * msMin)) {
byte value = map(analogRead(sensor), sensorMin, sensorMax, 0, 255);
file.write(value);
delay(interval);
}

What I don't get is the line " if (file) { ".
If file what ? I know it means "If file (is true)" - but that isn't much help ! I'm used to seeing something like "If (a == 5)".

I have a feeling my confusion is rooted in the phrase 'returns / creates an instance' and I'm testing for that with the 'if (file)' statement.... but I'm not sure !

Any pointers would be greatly appreciated !

Thanks !

aneng:
If file what ?

If file is true. True means non zero. If SD.open is successful, a non-zero value is returned. If its not, a 0 is returned which evaluates to false.

if (18)

always runs the code in the if block because 18 is non zero.

if (0)

never runs the code in the if block

aneng:
I'm kind of stuck at a bit about IF loops.

That's hardly surprising since there is no such thing as an IF loop.

If file is true.

No, as file is an instance of File, it should be read as file is not null.

Mark

holmes4:

If file is true.

No, as file is an instance of File, it should be read as file is not null.

Mark

Depends on if you're looking at it from the perspective of the File instance or the if statement

Ive added some comments to your code in an attempt to make it more clear:

file = SD.open("data.txt", FILE_WRITE);     // Try to open the file named data.txt in the current directory. If the attempt fails (i.e., file doesn't exist or just can't open it) 
                                                          // return 0, otherwise return a file handle

if (file) {                          // This is the same as: if (file != 0), which means if we successfully opened the file...

  while (millis() < (runningTime * msMin)) {           // Good practice to indent if and while statements...
      byte value = map(analogRead(sensor), sensorMin, sensorMax, 0, 255);  // read a sensor value as a byte value...
      file.write(value);                      // Write the value to the data.txt file...
      delay(interval);                        // delay processing for a while...
   }                                              // end of while loop statement block
}                                                 // end if statement block

Actually, "returns an instance" is an Object Oriented Programming idiom that usually refers to an object that was defined for a specific (C++) class. Right now, you might just think of it as a variable (e.g., the file variable in your code) that is either usable (i.e., its value is non-zero) or not usable (i.e., its value is zero).

To everyone:

In the code fragment:

   while (millis() < (runningTime * msMin)) {           
      byte value = map(analogRead(sensor), sensorMin, sensorMax, 0, 255);  
      file.write(value);                     
      delay(interval);                        
   }

How is the lvalue for value determined? That is, does value get a new (reallocated) memory address on each pass through the loop, or is just one allocation done regardless of the number of passes through the loop. (I'm away from home and don't have access to my development system.)

econjack:
How is the lvalue for value determined? That is, does value get a new (reallocated) memory address on each pass through the loop, or is just one allocation done regardless of the number of passes through the loop. (I'm away from home and don't have access to my development system.)

The value is redefined each time the loop is executed.

Whether the compiler actually allocates and releases the memory at the start and end of each loop, and whether the memory happens to be in the same place and happens still to contain the previous value, is a matter for the compiler's code generation algorithm. As far as you and I are concerned, the variable comes into existence when execution reaches the statement that defines it, and goes out of existence when execution reaches the end of the body of the for loop.

Many thanks to all, esp Econjack. I understand what it's doing now, though I'm still a little hazy on the 'instance' thing ! The last time I did any coding was in college, many (too many) decades ago, and that was in Borland 'Turbo' Pascal. :slight_smile:

aneng:
What I don't get is the line " if (file) { ".
If file what ? I know it means "If file (is true)" - but that isn't much help ! I'm used to seeing something like "If (a == 5)".

I have a feeling my confusion is rooted in the phrase 'returns / creates an instance' and I'm testing for that with the 'if (file)' statement.... but I'm not sure !

Moving onto facts ...

File is a class, and SD.open returns an instance of that class. For example, if dog is a class, Fido is an instance of the class dog.

Arrch:
If file is true. True means non zero. If SD.open is successful, a non-zero value is returned. If its not, a 0 is returned which evaluates to false.

This is not correct. It returns an instance of File. The instance always exists and is not zero. It is not any number.

holmes4:
No, as file is an instance of File, it should be read as file is not null.

Nor is it NULL or not NULL (it is not a pointer at all).


The answer is here:

class File : public Stream {
...

  operator bool();
...
};

The class File implements operator bool(). That means if you attempt to treat (an instance of) File as a boolean, for example:

if (file) ...

Then the operator bool() function is called.

This function is implemented thus (in the standard SD library):

File::operator bool() {
  if (_file) 
    return  _file->isOpen();
  return false;
}

So basically, if the file is successfully opened the private member variable _file is non-NULL. Otherwise it is NULL. The function tests for that (and if non-NULL if it is actually open) and returns true or false.

PeterH:
The value is redefined each time the loop is executed.

That's my understanding, too. My company produced C compilers back in the early 80's and, even though we considered our compiler to generate pretty good code, we did not optimize the allocation away inside a loop like the one shown above. Our feeling was that someone might do this kind of thing for debugging purposes. (The keyword volatile probably was created for situations where there was a reason for such things.) That said, I don't understand why the writer would want to reallocate value on each iteration through the loop. It would be better to define value just before entering the loop.

It is perfectly legitimate to re-initialize a variable every time through a loop. And I'm not sure that volatile is meaningful with auto variables.

I think it must be, since it's possible for an interrupt handler to modify the value.

I think it must be, since it's possible for an interrupt handler to modify the value.

How? An auto variable is local to one function. The ISR is another function. The ISR should not have access to the auto variable.

PaulS:
How? An auto variable is local to one function. The ISR is another function. The ISR should not have access to the auto variable.

It occupies memory so it is capable of being modified by code in an interrupt handler. You don't need visibility of the symbol in order to modify its value.

You don't need visibility of the symbol in order to modify its value.

You need some way of knowing that the symbol is located at some address. I guess you could have an auto variable pointed to by a global pointer.

PaulS:

You don't need visibility of the symbol in order to modify its value.

You need some way of knowing that the symbol is located at some address. I guess you could have an auto variable pointed to by a global pointer.

As long as you only refer to the global pointer while the function is active. If the function ever returns, all bets are off. Passing a pointer of an auto variable to a function that uses the pointer and then returns (but does not cache the pointer passed) is safe, but having references to variables that go out of scope is a problem.

Getting back to Aneng's original question, in Object Oriented Programming, a class is used to model something you're interested in. Nick used a dog as an example and then said that Fido is an instance of the dog class. The way I teach it is to think of class as a blueprint for whatever it is you're interested in. For example, consider a class named Cookie. Inside the class definition you have one or more properties that define the class. In the Cookie class, they might be angles used to define the "bends" in a sharp-edge metal. Define the values a certain way, and you get a Christmas tree cookie cutter. Define them a different way, you get a Star cookie cutter...and so on. So, the properties and methods defined within the class are a template that you can hang on the wall and use whenever you wish. Note, however, you have not defined a cookie yet. You've only created a set of blueprints for various types of cookies.

In Nick's example, you might have properties for a dog like weight, hair color, height, tail length, muzzle length, etc. The Dog class might have methods for Walking(), Barking(), Biting(), etc...things or actions the dog can do. Again, the Dog class is a template for "creating" a dog. My cookie class has properties that can be used to "create" a cookie.

If you think of blueprints as a class that defines a house, then using those blueprints creates an instance of a house. In computer terms, an instance of an object is really a chunk of memory that you can use in your program. Until you have an instance of an object, you don't have the object in usable form. Buying a set of house blueprints doesn't get you a house. If I define the Cookie class properties in a certain way, I am capable of creating a specific cookie. However, until I press the cookie cutter I have defined (i.e., the type of cookie as I have defined it in the class properties) into some cookie dough, I don't have a cookie. Getting back to your original question, if I take the defined cookie cutter (i.e., a class object) and press it into the dough (i.e., computer memory), I get a real cookie (i.e., an instance of the object). Only when I have an instance of a class can I use it in my program.

In Java, the statement:

Time myTime;

says I want to create an object of the Time class named myTime. This says I'm grabbing the Time cookie cutter off the wall that holds thousands of different class cookie cutters and I'm labeling it myTIme. However, it's only after I use the statement:

myTime = new Time();

that I take that cookie cutter and carve out a chunk of memory to create an instance of a Time cookie named myTime. IT's the keyword new that calls the class constructor that actually creates an instance of the cookie. (Usually, the two statements are collapsed into one.) Hopefully, this shows you the difference between a class definition and an instance of the class.

econjack:
In Java, the statement:

Time myTime;

says I want to create an object of the Time class named myTime. This says I'm grabbing the Time cookie cutter off the wall that holds thousands of different class cookie cutters and I'm labeling it myTIme.

Yes, but in C++ myTime is still an instance of Time. It is just created either on the stack (for an auto variable) or in static memory (if in global memory). The "new Time" creates an instance on the heap. They are both instances.

The major difference is the lifetime of the instance. In the case of a non-heap instance the instance is destroyed when it goes out of scope. For a heap instance the instance is destroyed when you delete it.

However, it's only after I use the statement:

myTime = new Time();

that I take that cookie cutter and carve out a chunk of memory to create an instance of a Time cookie named myTime

I gather you are talking about Java still. In C++ you would have to say:

Time * myTime = new Time;

To use "new" you need a pointer, hence the asterisk.

PaulS:

You don't need visibility of the symbol in order to modify its value.

You need some way of knowing that the symbol is located at some address. I guess you could have an auto variable pointed to by a global pointer.

Fully agree that it would be a strange thing to do, but the point is that it would be legal, so the compiler must support it.