POV-Ray : Newsgroups : povray.off-topic : C# 4.0 Default parameters Server Time
9 Oct 2024 14:38:58 EDT (-0400)
  C# 4.0 Default parameters (Message 11 to 20 of 56)  
<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>
From: Darren New
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:56:59
Message: <4989c8db@news.povray.org>
Invisible wrote:
 > * This is why, if a Haskell function takes any functions as arguments,
 > they invariably come *first*, and any data structures come *last*. ;-)

Technically, I would think you could have a curried function in a language 
with named parameters pretty easily.  It wouldn't have to be the first 
argument as long as you're making up a new language anyway. It would 
actually just wind up being the same kind of syntactic sugar that default 
parameters are.

> I don't know anything about it. 

They're just three different syntaxes for exactly the same thing, as the 
compiler evolved through different releases.

> I've only seen "delegates" in other 
> languages, where they're used because "callback functions are really 
> useful, but we don't want actual function pointers, so..."

One difference is that a delegate can point to either a static function, or 
to a instance function with its associated instance. So if you have a 
delegate xyz that takes a float and returns an int, you can have
    xyz = my_static_function;
    xyz = some_instance.instance_method;

Also, delegates are really lists of such pointers, and invoking it calls 
each one in turn. Your basic Observer pattern.

>> Lambda expressions are darned convenient. I used them in my little FFT 
>> toy app:
>>
>> RealInput.Data = GenerateWave(x => cos((Math.Pi*2*x)/(DataLen-1)));
> 
> They're also damned useful when you want to curry a function:
>   bar = foo (...my random lambda function that I only just here...)

That's where they're used in C#.

Note too that depending on the declaration of the argument you're passing 
the function to, your lambda expression in C# can actually wind up being a 
syntax tree instead of a function with actual machine code.  So you can 
write a routine that takes an AST, frobs it around to make a new AST, 
compiles it, and runs it. This is how the mechanisms for querying SQL from 
C# work - you can write something like
   db.table["customers"].select(x => x.Name > "Henry")
and the "select()" function takes the AST describing that condition, 
translates it to SQL, and sends it to the database.

>> FooBarBaz fb = new FooBarBaz() { foo = 123, bar = 4.56 };
>> Baz takes on the default value of "" (assuming its a string)

My understanding is that only works with properties. And of course Baz gets 
whatever the constructor sets it to, rather than necessarily an empty 
string. (Anyway, wouldn't it get null if not set?)

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

From: Darren New
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:58:31
Message: <4989c937$1@news.povray.org>
Mike Raiford wrote:
> Should cause a compiler warning about side effects. (I would think)

It's good side-effects, tho, yes? The complaint is valid in conditionals not 
because of side effects but because it's a constant value in a conditional.
   while (x = getchar()) {...}
doesn't cause a complaint, because getchar() isn't a constant.

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

From: Warp
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:04:43
Message: <4989caab@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> There are some who make good arguments against default parameters. 
> Basically, if it's a default parameter, it should be a separate method call 
> to set the value, because that's more OO.

  In an OO language where constructing an object also initializes it (so that
it's impossible to have uninitialized objects, which makes sense), it may be
rational to have more than one constructor for constructing objects in
different ways. It may also be rational to have a default-constructed object,
with some sensible default values. (And in some cases being able to
default-construct objects might be a prerequisite.)

  For example if you have a class named Point, which represents a
2-dimensional point with integer coordinates, it may be very rational
to have two constructors: A default constructor which initializes the
coordinates to zero, and another constructor which takes the values as
parameters. If we expressed that in C++, it would be:

class Point
{
 public:
    Point(); // Default constructor, initializes to (0,0)
    Point(int x, int y); // Initializes to the given values
};

  On the other hand, there isn't too much difference between that and:

class Point
{
 public:
    Point(int x = 0, int y = 0);
};

  Now the one and same constructor works both as the default constructor
and a constructor taking initial values.

  There may be one relevant difference from the point of view of the
implementation: Having only one constructor avoids code repetition,
especially if the constructor implementation is complicated.

  (OTOH, with the upcoming C++ standard it will be possible to call one
constructor from another, but until then...)

  One could argue: Why not have only the default constructor, and a
"set(int x, int y)" member function for setting the values?

  It becomes cumbersome when you need only a temporary, for example like:

    Point tmp;
    tmp.set(1, 2);
    foo(tmp);

rather than:

    foo(Point(1, 2));

  The former may also be harder for the compiler to optimize. The former
also makes it a lot more difficult to use move semantics (which might
become relevant if copying the objects is heavy).

  "Then don't use any default constructor at all, only the constructor
taking the parameters."

  However, then your class becomes less usable in situations like:

    std::vector<Point> vec;
    vec.resize(10); // Requires that Point has a default constructor

  Yes it's possible to give an object to the resize() function to initialize
the new objects from, but there may be situations where you just can't have
such a non-default-initialized object, such as:

    template<typename T>
    void foo()
    {
        std::vector<T> vec;
        vec.resize(10); // How would you know how to initialize an object
                        // of type T appropriately here?
    }

  Suppose the function is then called like: foo<Point>();

-- 
                                                          - Warp


Post a reply to this message

From: nemesis
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:06:42
Message: <4989cb22@news.povray.org>
Darren New escreveu:
> Mike Raiford wrote:
>> That is how C# is now. Sometimes it would be nice just to have one 
>> function with defaults, rather than 3 overloads of the same function 
>> that simply delegate back to the "full featured" function.
> 
> No, i mean instead of
>   job.print(orient:landscape, copies:2, paper:A4)
> the suggestion it that it's much more OO to say
>   job.initialize()
>   job.orient(landscape)
>   job.copies(2)
>   job.paper(A4)
>   job.print()

More OO, or more assemblyish?  I mean, you individually feed the stack 
and then call a function using those arguments already in the stack. ;)

seems we're going full cycle here... :P

Of course, assembly (and function currying in Haskell for that matter) 
expect arguments in the right order.  Named arguments and the above more 
OO and barroque way do not.


Post a reply to this message

From: Mike Raiford
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:13:02
Message: <4989cc9e$1@news.povray.org>
Darren New wrote:

>>> FooBarBaz fb = new FooBarBaz() { foo = 123, bar = 4.56 };
>>> Baz takes on the default value of "" (assuming its a string)
> 
> My understanding is that only works with properties. And of course Baz 
> gets whatever the constructor sets it to, rather than necessarily an 
> empty string. (Anyway, wouldn't it get null if not set?)
> 

Right on both counts. I think string actually gets set to String.Empty 
by default.

-- 
~Mike


Post a reply to this message

From: Darren New
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:14:49
Message: <4989cd09$1@news.povray.org>
nemesis wrote:
> More OO, or more assemblyish?  I mean, you individually feed the stack 
> and then call a function using those arguments already in the stack. ;)

Well, no, it's not a stack, it's an object. And each call can, for example, 
set error codes or throw exceptions or some such. So if there's no 
letter-sized paper loaded, the call to set letter size might throw an 
exception you could handle.

As I said, it has some drawbacks, but some benefits too, primarily in the 
areas of subclassing and reuse. Passing all the arguments you need to 
print() is the procedural way of doing it. Passing an object to print() with 
all the parameters set (and which you can, for example, clone and pass 
around) is the OO way to do it.

You could create the printjob object and initialize it in one library and 
invoke print() in another, which you can't do with the default-args approach.

> Named arguments and the above more OO and barroque way do not.

 From experience, it only seems baroque if you're not used to it. Once you 
realize the benefits, and you find that the benefits outweigh the verbosity, 
it's quite nice.

Kind of like the whole command/query separation.  A bit more verbose, but 
also more clear and maintainable. (Command/query separation is basically 
that only functions that don't return a value are allowed to modify the 
object. Or, in C++ terms, all non-const methods must be void.)

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

From: Darren New
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:25:47
Message: <4989cf9b$1@news.povray.org>
Warp wrote:
>   In an OO language where constructing an object also initializes it (so that
> it's impossible to have uninitialized objects, which makes sense), it may be
> rational to have more than one constructor for constructing objects in
> different ways. It may also be rational to have a default-constructed object,
> with some sensible default values. (And in some cases being able to
> default-construct objects might be a prerequisite.)

Agreed. This is the main situation where I find it's actually a PITA to 
follow the rule. :-) But usually for this sort of thing, your constructor 
doesn't take a whole lot of arguments, so making any of them default values 
would be reasonable.

I'd expect the best answer would be to have the default constructor (if it 
exists) not take any arguments and use a different name for constructors 
that take arguments. Calling Point.initialize(0,0) would be just like 
calling Point.new().

Of course, using default arguments assumes that there *is* a valid default. 
Unless your language supports telling you which arguments didn't get passed 
from the caller, you sometimes *have* to use the separate-call pattern.

>     Point(); // Default constructor, initializes to (0,0)
>     Point(int x, int y); // Initializes to the given values

The same guy also thinks overloaded function names are a bad idea, too, 
altho his reasoning on that seems less obvious.  (Other than when you 
inherit, you wind up with problems if you want to override one version and 
not the other, I guess.)

>   It becomes cumbersome when you need only a temporary, for example like:

I don't think the original proponent (Meyers) was too worried about 
cumbersome as much as he was about correctness and reusability. :-)

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

From: Warp
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:27:35
Message: <4989d007@news.povray.org>
Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
> At least in C# you can't do function pointers.

  There are situations where function pointers are actually useful.
Here's one actual example which I have used in the past (simplified here,
of course):

class MyCLP: public CommandLineParser
{
    bool debugParamHandler(const std::string&)
    {
        // do whatever here
    }

 public:
    MyCLP()
    {
        setOptionHandler("debug", &MyCLP::debugParamHandler,
                         "The short description of the -debug parameter");
    }
};

  The idea is that 'CommandLineParser' is a class which parses the command
line parameters (in the project in question it parsed things like the input
and output file names as well as many default parameters supported by all
the programs in the project), and if you want to support a parameter specific
to this program, you specify it with the 'setOptionHandler' function. You
give the function the name of the parameter and a pointer to the function
which CommandLineParser should call when that parameter appears in the
command line.

  The internal implementation of CommandLineParser becomes a bit complicated
(for many reasons), but this is by far the best way from the *usage* point
of view. Any other solution would require to always write a lot more code
if you want to add support for a new command-line parameter. This solution
requires the minimum amount of code you have to write in order to do that.

  This doesn't mean this could be the only way of implementing this
functionality. It's just the simplest from the usage point of view.

  The next best thing would be to have just one generic virtual function
in the base class which gets called when a registered command-line parameter
appears, and then you implement this virtual function. However, you would
have to implement it as a big if... else if... else if... else if... else
block, so it becomes more cumbersome than the way described above.

  Another example of where a function pointer can be handy is when wanting
to supply a comparator to a STL algorithm or data container.

  For example, suppose that you want to sort an array of objects in a
special way (or simply if the objects don't support the < comparison).
What to do? What you do with the STL is:

    std::sort(array.begin(), array.end(), objectComparator);

  Now a comparator is "anything that behaves like a function taking two
const references to array elements, and returns a bool". The most obvious
thing which behaves like that is a *function* with that signature. For
example assuming that the element of the array is of type Object, you would
write such a function as:

    bool objectComparator(const Object& lhs, const Object& rhs)
    {
        // return true if lhs < rhs, else false
    }

  Now if you pass this function as the third parameter for std::sort(),
as above, what you are doing is actually passing a function pointer.
(If you look at the type id of the resulting std::sort() function, the
type of the third parameter will indeed be a function pointer with that
signature.)

  It's possible to create an object which behaves like such a function
(a functor object), but it's more writing.

-- 
                                                          - Warp


Post a reply to this message

From: nemesis
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:29:47
Message: <4989d08b$1@news.povray.org>
Darren New escreveu:
> nemesis wrote:
>> More OO, or more assemblyish?  I mean, you individually feed the stack 
>> and then call a function using those arguments already in the stack. ;)
> 
> Well, no, it's not a stack, it's an object. And each call can, for 
> example, set error codes or throw exceptions or some such. So if there's 
> no letter-sized paper loaded

It's a saved stack, let's say.

> Kind of like the whole command/query separation.  A bit more verbose, 
> but also more clear and maintainable. (Command/query separation is 
> basically that only functions that don't return a value are allowed to 
> modify the object. Or, in C++ terms, all non-const methods must be void.)

I don't like the whole OO BS.  Despite being submitted to it daily for 
the last 20 years or so.  Functional programming and scripting too 
opened my eyes to a much better model for software programming.


Post a reply to this message

From: Darren New
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 12:35:56
Message: <4989d1fc$1@news.povray.org>
Warp wrote:
> Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
>> At least in C# you can't do function pointers.
> 
>   There are situations where function pointers are actually useful.

To be clear, C#'s "delegates" are actually a superset of the functionality 
of "function pointers". C# wouldn't have any problem with implementing your 
examples.

>   The next best thing would be to have just one generic virtual function
> in the base class which gets called when a registered command-line parameter
> appears, and then you implement this virtual function. However, you would
> have to implement it as a big if... else if... else if... else if... else
> block, so it becomes more cumbersome than the way described above.

I think better would be the way you wind up having to do it in Java - you 
have a class that implements a "parse this" method for each possible 
argument to be parsed, and the parser has a map from "-debug" to an instance 
of the class that parses the debug parameter.  So you have one subclass for 
each parser function.  Ugly, but not as bad as a giant switch statement.

FWIW, a delegate *is* an object that behaves like a function (your "functor 
object").  You write something like

delegate int xyz(float);

int doodoo(float x) { return (int) (x*x); }

xyz = doodoo;

int answer = xyz(27.3);

You can also then say

int foofoo(float y) { return (int) (y * 18.2); }

xyz += foofoo;

Then when you call
xyz(71.3);
it passes 71.3 to doodoo then to foofoo.

Less helpful if you actually need the results, but often delegates are used 
as things like callbacks for user interface frobbings or other async events, 
so failures tend to be propagated back as exceptions rather than return results.

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

<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>

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