POV-Ray : Newsgroups : povray.off-topic : C# 4.0 Default parameters : Re: C# 4.0 Default parameters Server Time
6 Sep 2024 13:21:17 EDT (-0400)
  Re: C# 4.0 Default parameters  
From: Darren New
Date: 6 Feb 2009 13:49:16
Message: <498c862c$1@news.povray.org>
Warp wrote:
>   So if setting a parameter to a given value can fail, you can't check
> the success/failure of the function call by having the function return
> eg. a boolean value informing of this, but instead you have to write a
> separate function which you have to call in order to query whether the
> operation was successful or not? And this for each such parameter which
> can fail?

Well, there's two kinds of "setting it failed". One is (for example) setting 
a printer to use a certain kind of paper. Here you can't tell before you try 
that it's going to fail (assuming it "fails" if that sort of paper isn't in 
the printer the moment you set it).

The other kind is (for example) popping the stack on an empty stack, which 
you can tell will fail before you even try it. In this case, it's considered 
a programming error on the part of the caller to even attempt to pop an 
empty stack.

The recommendation that queries and commands be separate is it keeps you 
from having to put it in a variable that's unrelated to the object you're 
calling. Why would the 'did the paper setting function work' value ever be 
stored in the local variables of the function that generates the report, 
rather than in the object that represents the printer itself?

It also means that you can have one part of you code intialize the printer 
and another part check it's ready to go, without passing printer-specific 
values around in code that hasn't anything to do with the printer. It's more 
a "big program" sort of technique, along the same lines as "each object 
should be responsible for only one thing" sort of thing. The object takes 
full responsibility for tracking all its state, and you query the object for 
its state every single time you need to know it. If you return status from 
mutating calls, you're passing responsibility for tracking the status back 
to the caller instead of encapsulating it in the object.

>   This presents a multitude of problems. For instance, the class would
> have to store booleans for each parameter somewhere, so that the "did
> the setting of that parameter succeed?" function can return it.

Right. Or, the caller has to do that when they call the function.

The function still has to save that information, because if setting the 
paper size failed, you can't print to the printer, right?  If you *can* 
print to the printer, then it isn't "did the paper setting fail?", but 
"after I told you to use A4, what paper size will you use?" It's only a 
"failure" if the caller can't accept the paper size the printer's ready to use.

For example: if you set the paper size, the object still has to know what 
the paper size is.  If you can have a type with a distinguished value (like 
NULL in C), you can have the function that returns the paper size return 
NULL if the paper size didn't get set correctly, for example.

Look at something like the getchar() function in C. How often do you use 
that where you don't have to assign it to a variable to use it? Not very 
often. You always wind up writing something like
   while ((c = getchar()) != EOF) { do something with c }

Instead, the recommendation is to use the equivalent of
   readchar();
   while (currentchar() != EOF) {
     do something with currentchar()
     and something else with currentchar()
     readchar();
   }

It's a little more verbose, but the "current character" stays with the 
object it's associated with. When you start putting distinguished-caller 
syntax in the mix, it becomes a lot easier to understand what's going on 
when you're in maintenance mode.  Like, say you're comparing two lists:

    one.initlist();
    two.initlist();
    while (one.curr() != two.curr()) {
      if (one.curr() < two.curr()) one.nextitem();
      else if (two.curr() < one.curr()) two.nextitem();
    }

If "nextitem" returned the next item of the list, the logic would be 
somewhat more convoluted, trying to keep the local variables synchronized 
with the contents of the lists, and it would be easy to accidentally assign 
two.nextitem() to m_one or something.


>   What if the success query function is called *before* the setting of
> the parameter function is called? Can the return value have a meaningful
> interpretation anymore?

I imagine it depends on the function. If it's initialized to a default that 
works (like whatever paper size happens to be loaded), then the "will this 
work" function would return true. If it's initialized to a value that's 
invalid (like the name of the file on a closed file handle) then the "will 
this work" function returns false.  The constructor has to assure that the 
query functions are valid, just like any other initialization the 
constructor needs to do.

-- 
   Darren New, San Diego CA, USA (PST)
   "Ouch ouch ouch!"
   "What's wrong? Noodles too hot?"
   "No, I have Chopstick Tunnel Syndrome."


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.