POV-Ray : Newsgroups : povray.off-topic : C# 4.0 Default parameters Server Time
9 Oct 2024 21:18:47 EDT (-0400)
  C# 4.0 Default parameters (Message 7 to 16 of 56)  
<<< Previous 6 Messages Goto Latest 10 Messages Next 10 Messages >>>
From: Invisible
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:18:25
Message: <4989bfd1$1@news.povray.org>
>>> 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.  E.g., if you 
>>> have a default parameter for printing that says whether it should be 
>>> landscape or portrait, that should be a value in the print-job 
>>> instance, not a parameter specified on every call.
>>
>> What *you* need is curried functions! ;-)
> 
> Explain curried functions, please.

First, I would like to begin by pointing out that that was a "joke". It 
wouldn't really solve the problem you're talking about.

However...

If you have a function like PrintMyStuff() which takes a bazillion 
arguments, the first on which is a portrate/landscape setting, you could 
"curry" that function like so

   DefaultPrintMyStuff = PrintMyStuff(PS_LANDSCAPE);

Now the new function DefaultPrintMyStuff() is just like the original 
PrintMyStuff(), except with the first parameter locked to landscape-mode.

In other words, it's a shortcut way to write those "functions with fewer 
arguments that just supply some defaults before calling the real-work 
function". (But notice you can only curry the *first* argument or 
argument(s), not some arbitrary set of them.)

>> Well... it was based on C to start with, so it's never going to be 
>> exactly "pretty", is it?
> 
> At least in C# you can't do function pointers.

Heh, well OK. Of course, the problem isn't so much function pointers, 
but rather that the syntax C uses for function pointers is clinically 
insane! :-D

Haskell, on the other hand, passes functions around all over the place 
routinely. But it has a far more sane syntax for them. ;-)



Interestingly, while Haskell doesn't allow named arguments, optional 
arguments or default arguments, it does give you something let is 
arguably similar / more useful: a flexible syntax for constructing records.

For example, instead of PrintMyStuff() having a bazillion parameters 
specifying portrate/landscape, paper size, base font, margins, etc., you 
have a record structure describing all the printing options. 
PrintMyStuff() now takes two arguments: the printing options and the 
stuff to print. (Remember, Haskell is *not* object-oriented.)

Record values can be constructed like this:

   PrintOptions {orientation = Portrate, paper_size = A4}

What this *doesn't* have is default values; any field you don't specify 
is undefined. (In C, that means you don't know what it will contain, but 
in Haskell it means accessing it throws an exception - which can be 
caught.) But what you *can* do is define a default_print_options value, 
and then use the incrimental modification syntax:

   PrintMyStuff(default_print_options {orientation = Landscape}, stuff)

This gives you the options in default_print_options, except that the 
orientation (only) is modified. All others remain at defaults.

Of course, as soon as your printing options are a *data structure* 
rather than a huge list of function arguments, it's possible to write 
*functions* to generate useful common combinations, and so on and so 
forth...

But sometimes, sure, it's probably easier to just have a damned default 
argument! ;-)


Post a reply to this message

From: Mike Raiford
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:31:22
Message: <4989c2da@news.povray.org>
Invisible wrote:

> 
> First, I would like to begin by pointing out that that was a "joke". It 
> wouldn't really solve the problem you're talking about.
> 
> However...
> 
> If you have a function like PrintMyStuff() which takes a bazillion 
> arguments, the first on which is a portrate/landscape setting, you could 
> "curry" that function like so
> 
>   DefaultPrintMyStuff = PrintMyStuff(PS_LANDSCAPE);
> 
> Now the new function DefaultPrintMyStuff() is just like the original 
> PrintMyStuff(), except with the first parameter locked to landscape-mode.

A joke, but very apropos. :)

> Heh, well OK. Of course, the problem isn't so much function pointers, 
> but rather that the syntax C uses for function pointers is clinically 
> insane! :-D
> 
> Haskell, on the other hand, passes functions around all over the place 
> routinely. But it has a far more sane syntax for them. ;-)
> 

C# has delegates, instead of function pointers.. which use a bit cleaner 
syntax.

Delgates have sort of evolved from named, to anonymous, to lambda.

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



> 
> 
> Interestingly, while Haskell doesn't allow named arguments, optional 
> arguments or default arguments, it does give you something let is 
> arguably similar / more useful: a flexible syntax for constructing records.
> 
> For example, instead of PrintMyStuff() having a bazillion parameters 
> specifying portrate/landscape, paper size, base font, margins, etc., you 
> have a record structure describing all the printing options. 
> PrintMyStuff() now takes two arguments: the printing options and the 
> stuff to print. (Remember, Haskell is *not* object-oriented.)
> 
> Record values can be constructed like this:
> 
>   PrintOptions {orientation = Portrate, paper_size = A4}

C# does that, too...

// Behold the Anonymous Type.
var val = new { foo= 123, bar = 4.56, baz = "Hello world!" };

> What this *doesn't* have is default values; any field you don't specify 
> is undefined. (In C, that means you don't know what it will contain, but 
> in Haskell it means accessing it throws an exception - which can be 
> caught.) But what you *can* do is define a default_print_options value, 
> and then use the incrimental modification syntax:

>   PrintMyStuff(default_print_options {orientation = Landscape}, stuff)
> 
> This gives you the options in default_print_options, except that the 
> orientation (only) is modified. All others remain at defaults.
> 
> Of course, as soon as your printing options are a *data structure* 
> rather than a huge list of function arguments, it's possible to write 
> *functions* to generate useful common combinations, and so on and so 
> forth...

Accessing a field not defined above results in a compile error. Of 
course, if you have an already defined type, you can set 
properties/fields in much the same way

FooBarBaz fb = new FooBarBaz() { foo = 123, bar = 4.56 };

Baz takes on the default value of "" (assuming its a string)


> But sometimes, sure, it's probably easier to just have a damned default 
> argument! ;-)

I can't believe how similar the syntax is on that. C# is getting to be 
more and more a C-like language with some functional stuff sprinkled in 
here and there.


-- 
~Mike


Post a reply to this message

From: Mike Raiford
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:35:29
Message: <4989c3d1$1@news.povray.org>
Darren New wrote:

> 
> Errr, they are? No. A C++ thing, but not a C thing.
> 

Oh. For some reason I thought they were introduced in C.

> 
> I think he screwed it up, is what I'm saying.
> 

Heh. Probably.

> list.Search(address="home")
> assigns "home" to address, then passes it to list.Search()
> 
> I wonder how often that's going to bite someone. :-) Lots, I expect.
> 

Should cause a compiler warning about side effects. (I would think)

-- 
~Mike


Post a reply to this message

From: Invisible
Subject: Re: C# 4.0 Default parameters
Date: 4 Feb 2009 11:45:13
Message: <4989c619$1@news.povray.org>
>> First, I would like to begin by pointing out that that was a "joke". 
>> It wouldn't really solve the problem you're talking about.
>>
>> However...
>>
>> If you have a function like PrintMyStuff() which takes a bazillion 
>> arguments, the first on which is a portrate/landscape setting, you 
>> could "curry" that function like so
>>
>>   DefaultPrintMyStuff = PrintMyStuff(PS_LANDSCAPE);
>>
>> Now the new function DefaultPrintMyStuff() is just like the original 
>> PrintMyStuff(), except with the first parameter locked to landscape-mode.
> 
> A joke, but very apropos. :)

Hmm. ;-)

Of course, in Haskell it's used more like this...

* You have a function called foo which takes two arguments - a function, 
and a list - and processing the list in some way based on what the 
function is.

* You make a list processing function by saying

   bar = foo my_function

(Remembering Haskell's unauthodox function-call syntax.)

* This is why, if a Haskell function takes any functions as arguments, 
they invariably come *first*, and any data structures come *last*. ;-)

>> Heh, well OK. Of course, the problem isn't so much function pointers, 
>> but rather that the syntax C uses for function pointers is clinically 
>> insane! :-D
>>
>> Haskell, on the other hand, passes functions around all over the place 
>> routinely. But it has a far more sane syntax for them. ;-)
> 
> C# has delegates, instead of function pointers.. which use a bit cleaner 
> syntax.

Haskell has... well, sort-of function references, if you will. Haskell 
doesn't have *pointers* (that can be null and that do arithmetic) 
anywhere, only references (which are never null, always point to 
something valid, can't be pointed to something else because they're 
immutable). Oh, and Haskell is rigidly typed. There is no typecast 
construct in the language.

> Delgates have sort of evolved from named, to anonymous, to lambda.

I don't know anything about it. 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..."

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

>> Record values can be constructed like this:
>>
>>   PrintOptions {orientation = Portrate, paper_size = A4}
> 
> C# does that, too...
> 
> // Behold the Anonymous Type.
> var val = new { foo= 123, bar = 4.56, baz = "Hello world!" };

Yeah, Haskell doesn't allow that. Types *must* be fully defined before 
you can use them. But once defined, the syntax is the same.

>> What this *doesn't* have is default values; any field you don't 
>> specify is undefined.
> 
> Accessing a field not defined above results in a compile error. Of 
> course, if you have an already defined type, you can set 
> properties/fields in much the same way
> 
> FooBarBaz fb = new FooBarBaz() { foo = 123, bar = 4.56 };
> 
> Baz takes on the default value of "" (assuming its a string)

Yeah, I meant more if you have a type that has fields X, Y and Z, and 
you construct a value of that type but don't specify the value for Z, if 
you try to access Z an exception is thrown.

> I can't believe how similar the syntax is on that. C# is getting to be 
> more and more a C-like language with some functional stuff sprinkled in 
> here and there.

Yeah, looks like in about 8 years or so C# or Python or Ruby will have 
stolen everything that is cool about Haskell, and Haskell itself *still* 
won't be popular. :-(

Which is a pitty, really, because few things can match the beauty and 
simplicity of Haskell...


Post a reply to this message

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

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

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