 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
http://tinyurl.com/bt268c
Let me just say: About time! I get tired of writing a bunch of overloads
to make parameters look like they're optional!
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford wrote:
> http://tinyurl.com/bt268c
>
> Let me just say: About time! I get tired of writing a bunch of overloads
> to make parameters look like they're optional!
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.
Sadly, C# syntax is starting to get really ugly. :-) I expect the
overloading rules will soon almost be as bad as C++.
> list.SearchForContacts(address="home", name="sam", age:30);
Heh. My first thought on seeing the syntax was "I bet I'd always be messing
that up and using = instead of :".
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New 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. 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! ;-)
> Sadly, C# syntax is starting to get really ugly. :-) I expect the
> overloading rules will soon almost be as bad as C++.
Well... it was based on C to start with, so it's never going to be
exactly "pretty", is it?
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible wrote:
> Darren New 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. 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.
>> Sadly, C# syntax is starting to get really ugly. :-) I expect the
>> overloading rules will soon almost be as bad as C++.
>
> 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.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> Mike Raiford wrote:
>> http://tinyurl.com/bt268c
>>
>> Let me just say: About time! I get tired of writing a bunch of
>> overloads to make parameters look like they're optional!
>
> 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.
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.
> Sadly, C# syntax is starting to get really ugly. :-) I expect the
> overloading rules will soon almost be as bad as C++.
Yep. Default parameters are a C thing.. :D Maybe that's why I like them...
> > list.SearchForContacts(address="home", name="sam", age:30);
>
> Heh. My first thought on seeing the syntax was "I bet I'd always be
> messing that up and using = instead of :".
>
I've never been very fond of the named arguments syntax. I'm sure some
people love it. BTW, why are strings passed with "=" and numbers passed
with ":"?
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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()
job.copies has no optional parameters, nor does job.paper, nor job.print.
(Of course, with properties, those could all look like assignments too)
Having three overloaded functions that delegate back to the full one is also
the "wrong" way. Just don't call the set-up function anyway, and have the
constructor set up the default arguments like it should.
The advantage is that if you have 20 possible settings, and you add 3 more,
you just write three new methods to set them and initialize them in the
constructor and you know none of the calls need to be adjusted.
Note that I'm simply presenting a point of view, not arguing that it's
necessarily right. Altho IME doing things this way always seems to lead to
cleaner (altho more verbose) code.
>> Sadly, C# syntax is starting to get really ugly. :-) I expect the
>> overloading rules will soon almost be as bad as C++.
>
> Yep. Default parameters are a C thing.. :D Maybe that's why I like them...
Errr, they are? No. A C++ thing, but not a C thing.
>> > list.SearchForContacts(address="home", name="sam", age:30);
>>
>> Heh. My first thought on seeing the syntax was "I bet I'd always be
>> messing that up and using = instead of :".
>>
>
> I've never been very fond of the named arguments syntax. I'm sure some
> people love it. BTW, why are strings passed with "=" and numbers passed
> with ":"?
I think he screwed it up, is what I'm saying.
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.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>>> 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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> 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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> 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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible escreveu:
> * This is why, if a Haskell function takes any functions as arguments,
> they invariably come *first*, and any data structures come *last*. ;-)
Hmm, this is just a convention, I guess. There's no technical
limitation for a function not appearing last in the argument list.
> 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...
Well, C# can because Microsoft employs the father of Haskell. ;)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford escreveu:
> 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.
huhuhu
C requires much more effort from a programmer aside from assembly... :P
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis wrote:
> It's a saved stack, let's say.
Uh, no. It's an object. A stack is LIFO, for one thing.
It's a stack only in the sense that if you pass a bunch of parameters to a
function, the function gets a pointer to where they are contiguous in memory
when you invoke the function, not unlike invoking a member method.
> 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.
Yah. It's handy for some things, like where OO is natural. It can be
annoying to try to squeeze functional stuff (like, say, the relational
model) into an OO framework. Most of my code is still procedural, and most
OO code I see (in things like web page servers etc) really doesn't need to
be OO anyway.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
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.
> 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");
> }
> };
>
C# uses delegates, instead. Similar functionality Not as ugly to
declare. Function pointer syntax can get ugly.
>
> std::sort(array.begin(), array.end(), objectComparator);
>
Again, very similar to the predicates used in C#'s extension functions,
which take delegates.
>
> It's possible to create an object which behaves like such a function
> (a functor object), but it's more writing.
>
Which is essentially a delegate :)
I was mainly alluding to the messiness of declaring function pointers.
C# does have a mechanism to do what you've described, though.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> 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.
What is the difference between a multicast delegate, as shown here, and
an event?
Love the function names, btw..
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis wrote:
> Mike Raiford escreveu:
>> 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.
>
> huhuhu
>
> C requires much more effort from a programmer aside from assembly... :P
Considering I started with C++, It's easy for me to blur the lines,
sometimes. I remember declaring structs in C being rather weird.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> 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.
Actually that's the most cumbersome solution (especially if you wanted
all the options inside one single class, rather than having one class per
option, which makes retrieving the values of the options more laborious)
and the one which requires most extra writing.
Yes, I considered many possible solutions when I implemented that command
line parser class, and found that the function (or rather method) pointer
solution was the best, from the usage point of view. The classes derived
from the parser class can be made simple, short and easy to read.
> FWIW, a delegate *is* an object that behaves like a function (your "functor
> object"). You write something like
Does it also work for member functions?
Member function pointers are a bit complicated in C++, but they can
be useful (as in my command line parser example). Obviously to call a
member function of a class through a pointer you need also the object for
which the function is called. The syntax for calling such a function is:
object.*functionPointer(parameters);
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
> C# uses delegates, instead.
How do they work for member functions?
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
> I remember declaring structs in C being rather weird.
The problem with C structs is that whenever you want to use them, you
have to say so. In other words, this works in C++, but not in C:
struct Foo { whatever; };
void bar()
{
Foo foo; // Doesn't work in C
}
Instead, you have to write:
struct Foo foo; // Works in both C++ and C
However, there's a workaround in C (which also works in C++, because of
the backwards compatiblity):
typedef struct { whatever; } Foo;
Now you can use "Foo" without having to put the "struct" before it every
time.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis <nam### [at] gmail com> wrote:
> 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.
Yet most functional programming languages support objects in one way
or another.
The fact is: If a programming language supports types, if it also
supports abstract user-defined types, it becomes an order of magnitude
more expressive and useful. And abstract user-defined types are objects
(in the OO sense).
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
>> C# uses delegates, instead.
>
> How do they work for member functions?
>
Transparently.
e.g.
delegate void myDel(int x);
class SomeClass
{
public int myValue;
public void DoInstanceStuff(int x)
{
myValue = x;
}
public static void Main()
{
SomeClass c = new SomeClass();
myDel d = c.DoInstanceStuff
d(6); // this sets c.myValue to 6;
}
}
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp escreveu:
> The fact is: If a programming language supports types, if it also
> supports abstract user-defined types, it becomes an order of magnitude
> more expressive and useful. And abstract user-defined types are objects
> (in the OO sense).
But that's within a function composition environment. I don't like OO's
step-by-step, verbose and multilayered approach of redundancy. I also
don't like all the naming conventions done for the sake of stupid,
easily replaceable drones programming in big enterprises, like as if
they were programming in notepad rather than in contextful high-end
IDEs. Then again, perhaps even Haskell would follow the same fate were
it to be endorsed by the industry...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford wrote:
> What is the difference between a multicast delegate, as shown here, and
> an event?
An event is a delegate with only += and -= exposed outside the class. I.e.,
declaring an event vs a delegate is like declaring a protected member vs a
public member. Same type of object, different visibility for callers.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> 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.
>
> Actually that's the most cumbersome solution
OK. By "better" I meant perhaps "more maintainable" or "more reusable" or
"more OO". The way I suggested lets you easily reuse the parser classes in
other programs, for example. I can write a "-geom" parser and you can write
a "-regex" parser, and Fred can combine them into one program easily.
>> FWIW, a delegate *is* an object that behaves like a function (your "functor
>> object"). You write something like
>
> Does it also work for member functions?
Yes. Anything that'll take a float and return an integer works. So you can
combine a static function that takes a float and returns an integer, plus a
member function that takes an instance (as a distinguised parameter, i.e.,
in "o.xyz()" syntax) and a float and returns an integer, and have them both
in the delegate at the same time.
> Member function pointers are a bit complicated in C++, but they can
> be useful (as in my command line parser example). Obviously to call a
> member function of a class through a pointer you need also the object for
> which the function is called. The syntax for calling such a function is:
>
> object.*functionPointer(parameters);
Yah. A C# delegate wraps up both the instance and the member method in one
syntax. So you'd say
class Thing {
static public int pdq(float y) { ... }
public abc(float z) { return (int) (z*this.stuff); }
int stuff;
Thing() { stuff = 28; }
}
Thing o = new Thing();
delegate int xyz(float x);
xyz = Thing.pdq;
xyz += o.abc;
xyz(27.3); // I think this will return the result of calling o.abc(27.3)
Pretty handy.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> Pretty handy.
Actually, what's annoying is that a null delegate doesn't just do nothing
when you invoke it. I've never seen a delegate invoked that wasn't guarded with
if (myptr != null) myptr(...);
Stupid design flaw there, methinks.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> * This is why, if a Haskell function takes any functions as arguments,
>> they invariably come *first*, and any data structures come *last*. ;-)
>
> Hmm, this is just a convention, I guess. There's no technical
> limitation for a function not appearing last in the argument list.
Oh, sure. Purely a convention. But currying is the reason why this
particular convention is there. That's all I'm saying.
>> 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. :-(
>
> Well, C# can because Microsoft employs the father of Haskell. ;)
Well, actually *anybody* who's read about how Haskell works can copy its
design. (Although *implementing* it well is non-trivial...)
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New wrote:
> Technically, I would think you could have a curried function in a
> language with named parameters pretty easily.
Yeah, I don't see why not. It's only a shortcut for creating a closure...
>>> 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#.
I didn't think C# had curried functions like my example.
> 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.
Lisp would be proud.
Does this transformation happen at compile-time or runtime?
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Darren New <dne### [at] san rr com> wrote:
> class Thing {
> static public int pdq(float y) { ... }
> public abc(float z) { return (int) (z*this.stuff); }
> int stuff;
> Thing() { stuff = 28; }
> }
> Thing o = new Thing();
> delegate int xyz(float x);
> xyz = Thing.pdq;
> xyz += o.abc;
> xyz(27.3); // I think this will return the result of calling o.abc(27.3)
> Pretty handy.
What if you want to call the function (through the pointer) for different
objects? I mean like you would write in C++:
Object obj1, obj2;
obj1.*funcPtr(param);
obj2.*funcPtr(param);
The same member function is called, but for different objects. (Thus if
the function in question eg. changes the state of the object, it happens
to the specified object.)
Curiously, you can even have pointers-to-member-variables in C++, and you
can then dereference the pointer on a per-object basis. That gets pretty
confusing pretty quick.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
> Transparently.
> e.g.
> delegate void myDel(int x);
> class SomeClass
> {
> public int myValue;
> public void DoInstanceStuff(int x)
> {
> myValue = x;
> }
> public static void Main()
> {
> SomeClass c = new SomeClass();
> myDel d = c.DoInstanceStuff
> d(6); // this sets c.myValue to 6;
> }
> }
So you can't use the same function delegate for calling a member
function of two different objects?
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis <nam### [at] gmail com> wrote:
> Warp escreveu:
> > The fact is: If a programming language supports types, if it also
> > supports abstract user-defined types, it becomes an order of magnitude
> > more expressive and useful. And abstract user-defined types are objects
> > (in the OO sense).
> But that's within a function composition environment.
Ah, so we avoid being related to the dreaded Object-Oriented Programming
(vade retro) by using different terminology for the same things. Then we
can write long lists of reasons why *our* terms do not *really* mean the
same things as the equivalent OOP terms.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> Mike Raiford <"m[raiford]!at"@gmail.com> wrote:
>> Transparently.
>
>> e.g.
>
>> delegate void myDel(int x);
>
>> class SomeClass
>> {
>> public int myValue;
>
>> public void DoInstanceStuff(int x)
>> {
>> myValue = x;
>> }
>
>> public static void Main()
>> {
>> SomeClass c = new SomeClass();
>
>> myDel d = c.DoInstanceStuff
>
>> d(6); // this sets c.myValue to 6;
>
>> }
>> }
>
> So you can't use the same function delegate for calling a member
> function of two different objects?
>
No, I don't think you can. The closest you could get would be something
like a multicast delegate. But, then you really cannot get a return value.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp escreveu:
> nemesis <nam### [at] gmail com> wrote:
>> But that's within a function composition environment.
>
> Ah, so we avoid being related to the dreaded Object-Oriented Programming
> (vade retro) by using different terminology for the same things. Then we
> can write long lists of reasons why *our* terms do not *really* mean the
> same things as the equivalent OOP terms.
Not that. I have no problem calling ADTs objects or parametrized
regions of code subroutines, functions, procedures, methods or whatever,
as long as it's not within a OO framework. I like functional
programming fluidity and lack of bureaucracy.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Orchid XP v8 wrote:
>> 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.
>
> Lisp would be proud.
>
> Does this transformation happen at compile-time or runtime?
>
Runtime, I believe. The select extension function for the IQueryable
interface takes an expression as its parameter. That expression object
is whats used to build the expression tree. LinqToSQL uses that to build
the SQL query.
--
~Mike
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis <nam### [at] gmail com> wrote:
> Not that. I have no problem calling ADTs objects or parametrized
> regions of code subroutines, functions, procedures, methods or whatever,
> as long as it's not within a OO framework. I like functional
> programming fluidity and lack of bureaucracy.
Well, I usually prefer encapsulation and abstraction over fancy
one-liners.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp escreveu:
> nemesis <nam### [at] gmail com> wrote:
>> Not that. I have no problem calling ADTs objects or parametrized
>> regions of code subroutines, functions, procedures, methods or whatever,
>> as long as it's not within a OO framework. I like functional
>> programming fluidity and lack of bureaucracy.
>
> Well, I usually prefer encapsulation and abstraction over fancy
> one-liners.
encapsulation and abstraction are conserved, thanks. :)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
nemesis <nam### [at] gmail com> wrote:
> Warp escreveu:
> > nemesis <nam### [at] gmail com> wrote:
> >> Not that. I have no problem calling ADTs objects or parametrized
> >> regions of code subroutines, functions, procedures, methods or whatever,
> >> as long as it's not within a OO framework. I like functional
> >> programming fluidity and lack of bureaucracy.
> >
> > Well, I usually prefer encapsulation and abstraction over fancy
> > one-liners.
> encapsulation and abstraction are conserved, thanks. :)
So you take what's great about OOP, rename it, and then say you hate OOP
and that it sucks, and that your own version is so much better.
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Orchid XP v8 wrote:
> Darren New wrote:
>> Technically, I would think you could have a curried function in a
>> language with named parameters pretty easily.
>
> Yeah, I don't see why not. It's only a shortcut for creating a closure...
I mean, if you have named parameters, it would seem pretty easy to have a
syntax for currying on any parameter.
>> That's where they're used in C#.
> I didn't think C# had curried functions like my example.
Yeah. Brain-oh. It does have closures, tho. Isn't that a very similar thing?
> Does this transformation happen at compile-time or runtime?
As far as I understand it, the AST is generated at compile time, but you can
compile it into actual machine code at runtime.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> What if you want to call the function (through the pointer) for different
> objects?
I can't think of a convenient way offhand to do this in C#. I think here
you'd likely fall back to a fixed-named function and then subclass objects
(or inherit from interfaces) to do that.
I never found the need to orthogonally specify a function and an object to
call it on, altho I imagine it might come up sometimes.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Warp wrote:
> So you take what's great about OOP, rename it, and then say you hate OOP
> and that it sucks, and that your own version is so much better.
The way code flows, yes, it's much better.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Mike Raiford wrote:
> No, I don't think you can. The closest you could get would be something
> like a multicast delegate. But, then you really cannot get a return value.
I think you'd have to do something like this. First, you need an interface
that defines all the possible functions you can call this way. That would be
the equivalent of making all the objects subclasses of the same class in C++.
interface Istuff {
int xyz(int x);
int pdq(int x);
}
// Then a class that inherits from Istuff
class Mine : Istuff {
int xyz(int x) { return x + 1; }
int pdq(int x) { return x - 1; }
}
// Declare the type of a delegate that takes the object and integer and runs
something.
delegate int do_it(Istuff on_what, int with_what);
// Declare two delegates, initializing them. One calls xyz, one calls pdq.
do_it use_xyz = ((Istuff on_what, int with_what) => on_what.xyz(with_what));
do_it use_pdq = ((Istuff on_what, int with_what) => on_what.pdq(with_what));
// Pick which one you want
void go_run_a_function(
inputted_bool ? use_xyz : use_pdq,
Istuff some_object, int parameter);
So, you can do it, basically by changing
blah(object, parameter)
into
object.blah(parameter)
with a lambda. But it's messy. Probably about as messy as going the other
way in C++. There's probably some fancy thing with generics you could do too.
--
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
|
 |
|  |
|  |
|
 |
|
 |
|  |
|
 |