www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Flag proposal

reply bearophile <bearophileHUGS lycos.com> writes:
Lutger Blijdestijn:

 Somebody one this newsgroup - maybe it was Don Clugston, also made a good 
 point against named parameters: it introduces inflexibility because now the 
 names of the parameters of a function become part of the public api. 
 Changing a name will now break client code.

Scala faces this problem: http://www.digitalmars.com/d/archives/digitalmars/D/Deprecated_argument_names_131514.html Bye, bearophile
Jun 10 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 5:53 PM, bearophile wrote:
 Lutger Blijdestijn:

 Somebody one this newsgroup - maybe it was Don Clugston, also made a good
 point against named parameters: it introduces inflexibility because now the
 names of the parameters of a function become part of the public api.
 Changing a name will now break client code.

Scala faces this problem: http://www.digitalmars.com/d/archives/digitalmars/D/Deprecated_argument_names_131514.html Bye, bearophile

That's good evidence that introducing named parameters would be quite involved. Andrei
Jun 10 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 That's good evidence that introducing named parameters would be quite involved.

It's also good evidence that Martin Odersky, one of the most intelligent language designers alive today, is willing to do a lot to support named arguments in his language :-) Probably implementing tuple unpacking syntax sugar too needs some not small changes, but they are well worth it (of those two features I think tuple unpacking syntax sugar is more important than named arguments). Anyway, in Scala this sub-feature isn't a custom language feature, it uses a general feature, annotations, that's used for several other purposes too. And I think C#4 doesn't have this sub-feature. Bye, bearophile
Jun 10 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 6:26 PM, bearophile wrote:
 Andrei:

 That's good evidence that introducing named parameters would be
 quite involved.

It's also good evidence that Martin Odersky, one of the most intelligent language designers alive today, is willing to do a lot to support named arguments in his language :-)

I have all respect for Odersky's competence, but that is beside the point. Design decisions are always taken in a context, and it's not impossible he would've had decided otherwise in a different context. D is a rich, powerful language _now_. It has classic features present in many languages, and a few features that are not present in many. Their full combination is not present in any other language, and creates a unique context. We've been historically trigger happy about discussing adding features in this group. This is not unique to D - all languages underwent the same process. But at this point it is a necessity that we start migrating our mindset from an endless wishlist - towards finding ingenious solutions within the language. Again, this is the case for every single language there is. Combining existing features towards new ends is in some ways more difficult than language design because you play within a confined ground, and I am a bit disappointed that a few posters have shown only contempt for such an effort.
 Probably implementing tuple unpacking syntax sugar too needs some not
 small changes, but they are well worth it (of those two features I
 think tuple unpacking syntax sugar is more important than named
 arguments).

What's wrong with myTuple.expand? Andrei
Jun 10 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 Design decisions are always taken in a context,

Right. But wasn't your comment about Scala named arguments complexity too out of context?
 But at this point it is a necessity that we start 
 migrating our mindset from an endless wishlist - towards finding 
 ingenious solutions within the language.

There are few basic features that are missing that are better as built-ins, even now. Tuple unpacking syntax sugar, named arguments, computed gotos, and few other smaller things. Do you want to freeze D language to D2 and not take a look at ideas for D3?
 and I am a bit disappointed that a few 
 posters have shown only contempt for such an effort.

You need to take a better look at the kind of people that are in this forum. People here are walking away from C++, Java (and even Python), looking for a feature-rich language that avoids some of the syntax kludges their former languages force them to use in their programs. So it's not so strange that people in this forum have on average a significantly lower tolerance to tricks like your Flag proposal. In a C++ forum your Flag idea probably is much more welcome, because compared to D programmers probably C++ programmers accept a higher level of noise and ugliness in their code :-)
 What's wrong with myTuple.expand?

It does nothing of what I need? Haven't we had this discussion already? I am having a huge deja-vu :-) I have discussed this topic several times already. Didn't you agree about the need of unpacking syntax sugar for tuples? I am confused now.................................. Bye, bearophile
Jun 10 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 7:04 PM, bearophile wrote:
 Andrei:

 Design decisions are always taken in a context,

Right. But wasn't your comment about Scala named arguments complexity too out of context?

What I did was to say that Don's and others' point, corroborated with the fact that Scala found it necessary to add that feature to the language, suggests that we need to worry about that.
 But at this point it is a necessity that we start migrating our
 mindset from an endless wishlist - towards finding ingenious
 solutions within the language.

There are few basic features that are missing that are better as built-ins, even now. Tuple unpacking syntax sugar, named arguments, computed gotos, and few other smaller things. Do you want to freeze D language to D2 and not take a look at ideas for D3?

Falling for either extreme would be a mistake.
 and I am a bit disappointed that a few posters have shown only
 contempt for such an effort.

You need to take a better look at the kind of people that are in this forum. People here are walking away from C++, Java (and even Python), looking for a feature-rich language that avoids some of the syntax kludges their former languages force them to use in their programs.

I'd love to see more evidence to this claim.
 So it's not so strange that people in this forum have on average a
 significantly lower tolerance to tricks like your Flag proposal. In a
 C++ forum your Flag idea probably is much more welcome, because
 compared to D programmers probably C++ programmers accept a higher
 level of noise and ugliness in their code :-)

I don't think that's the reason. You should have seen the C++ forums up until about 1997. They were brimming with enthusiastic proposals for language changes. Interesting work became possible after it became clear to everyone that the language is now given, so it's time to use what's there. D, too, is receiving an increasing amount of real work from the community since TDPL's publication.
 What's wrong with myTuple.expand?

It does nothing of what I need? Haven't we had this discussion already? I am having a huge deja-vu :-) I have discussed this topic several times already. Didn't you agree about the need of unpacking syntax sugar for tuples? I am confused now..................................

I must be the one confused, but at best we shouldn't spread ourselves too thin. Andrei
Jun 10 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 I'd love to see more evidence to this claim.

Right :-)
 Interesting work became possible after it became clear 
 to everyone that the language is now given, so it's time to use what's 
 there.

If you want to build stable large frameworks and libraries then having a "stable" (backwards compatible) language helps. But in this thread we are only talking about additive changes. And C#/Python show abundant code written even while C# was adding generics, dynamic, named arguments, and many other things (and C#5 will add more things), and the same has happened to Python too, since several years. Python is just out of a design hiatus meant to help other Python implementations catch up, and now new design ideas are discussed again. In D syntax sugar for tuple unpacking is useful for library programmers too. Bye, bearophile
Jun 10 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 8:31 PM, bearophile wrote:
 Andrei:

 I'd love to see more evidence to this claim.

Right :-)
 Interesting work became possible after it became clear to everyone
 that the language is now given, so it's time to use what's there.

If you want to build stable large frameworks and libraries then having a "stable" (backwards compatible) language helps. But in this thread we are only talking about additive changes.

Don't kid yourself. Every additive change creates more precedent and more reason to refuse thinking creatively within the language. It also means the language and its fostered idioms are a moving target.
 And C#/Python show
 abundant code written even while C# was adding generics, dynamic,
 named arguments, and many other things (and C#5 will add more
 things), and the same has happened to Python too, since several
 years. Python is just out of a design hiatus meant to help other
 Python implementations catch up, and now new design ideas are
 discussed again. In D syntax sugar for tuple unpacking is useful for
 library programmers too.

I think these languages are at a different point in their evolution than D. We still don't have a strong answer to "what are the largest apps written in D" and this is because many people with an interest in the language are paralyzed in analysis. I know the phenomenon: after you spend a lot discussing designs, it is downright frightening to commit to one. Andrei
Jun 10 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 7:09 PM, Jonathan M Davis wrote:
 I think that there _are_ features that we need to look at adding in some form
 or other (such as conditional attributes) in order to solve current problems
 in the language (such as the inability to use many attributes - such as pure
 and  safe - with templates without excessive duplication of code). But if a
 feature does not solve a pressing problem and/or can be reasonably solved by
 improving Phobos, then we should be improving Phobos.

Good point. Walter and I agree that there are two categories of language change: adding new features, and removing undue limitations. At this point, we're planning on a lot more of the latter than the former kind. As an example, consider: module my_module; void fun() { import std.random; return uniform(0, 100); } int gun() { import std.stdio; writeln(fun()); } This module won't compile in today's D, but not for a matter of principles; it's just a random limitation of the language. (It does work if you import from within a class or struct.) You can insert most declarations in a scope, so the ones you can't insert are just awkward exceptions, unless there's a good reason to actively disable them. Any code should work if you just wrap another scope around it. Walter and I call the above a "turtle feature", in allusion to the "turtles all the way down" meme. Walter wants to fix this, and similar limitations that act "unturtly". Imports inside a scope won't be visible outside that scope, and importing the same module from several different functions will come at no cost in compilation time. This may as well lead to a different approach to defining good D modules, in which many imports don't come at the top unless they are of very general use. Functions that have special needs can always embed their own imports modularly without the symbols spilling out in everyone else's sight. As a perk - remember Adam Ruppe's trick to build the examples on the site? Some have top-level code so they don't compile as they are. With this change, code should work if the website simply adds a unittest { ... } around the code. Andrei
Jun 10 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 This module won't compile in today's D, but not for a matter of 
 principles; it's just a random limitation of the language. (It does work 
 if you import from within a class or struct.) You can insert most 
 declarations in a scope, so the ones you can't insert are just awkward 
 exceptions, unless there's a good reason to actively disable them. Any 
 code should work if you just wrap another scope around it.
 
 Walter and I call the above a "turtle feature", in allusion to the 
 "turtles all the way down" meme. Walter wants to fix this, and similar 
 limitations that act "unturtly". Imports inside a scope won't be visible 
 outside that scope, and importing the same module from several different 
 functions will come at no cost in compilation time.

You are allowed to import modules inside functions in Python too (there is a just a minor restriction), but I have never asked for this feature in D because this feature has a cost too. Putting all imports at the top of the module is more tidy, it allows the person that reads the code to find all the used imports very quickly. If they are spread in the module they become less easy to find, you need to use your editor/IDE to search for them. Bye, bearophile
Jun 10 2011
next sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 6/11/11 3:21 AM, bearophile wrote:
 Andrei:

 This module won't compile in today's D, but not for a matter of
 principles; it's just a random limitation of the language. (It does work
 if you import from within a class or struct.) You can insert most
 declarations in a scope, so the ones you can't insert are just awkward
 exceptions, unless there's a good reason to actively disable them. Any
 code should work if you just wrap another scope around it.

 Walter and I call the above a "turtle feature", in allusion to the
 "turtles all the way down" meme. Walter wants to fix this, and similar
 limitations that act "unturtly". Imports inside a scope won't be visible
 outside that scope, and importing the same module from several different
 functions will come at no cost in compilation time.

You are allowed to import modules inside functions in Python too (there is a just a minor restriction), but I have never asked for this feature in D because this feature has a cost too. Putting all imports at the top of the module is more tidy, it allows the person that reads the code to find all the used imports very quickly. If they are spread in the module they become less easy to find, you need to use your editor/IDE to search for them. Bye, bearophile

At least allowing imports in unittests would be nice though – I frequently find myself writing »version (unittest) {}« blocks before the actual unit tests just to import some modules not needed during regular builds (yeah, I suppose I'm somewhat pedantic about that). David
Jun 10 2011
parent jdrewsen <jdrewsen nospam.com> writes:
Den 11-06-2011 03:26, David Nadlinger skrev:
 On 6/11/11 3:21 AM, bearophile wrote:
 Andrei:

 This module won't compile in today's D, but not for a matter of
 principles; it's just a random limitation of the language. (It does work
 if you import from within a class or struct.) You can insert most
 declarations in a scope, so the ones you can't insert are just awkward
 exceptions, unless there's a good reason to actively disable them. Any
 code should work if you just wrap another scope around it.

 Walter and I call the above a "turtle feature", in allusion to the
 "turtles all the way down" meme. Walter wants to fix this, and similar
 limitations that act "unturtly". Imports inside a scope won't be visible
 outside that scope, and importing the same module from several different
 functions will come at no cost in compilation time.

You are allowed to import modules inside functions in Python too (there is a just a minor restriction), but I have never asked for this feature in D because this feature has a cost too. Putting all imports at the top of the module is more tidy, it allows the person that reads the code to find all the used imports very quickly. If they are spread in the module they become less easy to find, you need to use your editor/IDE to search for them. Bye, bearophile

At least allowing imports in unittests would be nice though – I frequently find myself writing »version (unittest) {}« blocks before the actual unit tests just to import some modules not needed during regular builds (yeah, I suppose I'm somewhat pedantic about that).

+1
Jun 11 2011
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/10/2011 6:21 PM, bearophile wrote:
 You are allowed to import modules inside functions in Python too (there is a
 just a minor restriction), but I have never asked for this feature in D
 because this feature has a cost too. Putting all imports at the top of the
 module is more tidy, it allows the person that reads the code to find all the
 used imports very quickly. If they are spread in the module they become less
 easy to find, you need to use your editor/IDE to search for them.

What, there's a Python feature you don't like? :-) I suspect that way of thinking may go the way of the old C style of putting all your declarations at the top.
Jun 10 2011
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 8:21 PM, bearophile wrote:
 Andrei:

 This module won't compile in today's D, but not for a matter of
 principles; it's just a random limitation of the language. (It does work
 if you import from within a class or struct.) You can insert most
 declarations in a scope, so the ones you can't insert are just awkward
 exceptions, unless there's a good reason to actively disable them. Any
 code should work if you just wrap another scope around it.

 Walter and I call the above a "turtle feature", in allusion to the
 "turtles all the way down" meme. Walter wants to fix this, and similar
 limitations that act "unturtly". Imports inside a scope won't be visible
 outside that scope, and importing the same module from several different
 functions will come at no cost in compilation time.

You are allowed to import modules inside functions in Python too (there is a just a minor restriction), but I have never asked for this feature in D because this feature has a cost too. Putting all imports at the top of the module is more tidy, it allows the person that reads the code to find all the used imports very quickly. If they are spread in the module they become less easy to find, you need to use your editor/IDE to search for them. Bye, bearophile

Maybe you also care less about what you import. Similar arguments have been made for placing all variable declarations at the top of the function etc. It's unclear at this point how far local imports would go, but I see good advantages. Andrei
Jun 10 2011
prev sibling parent reply Lutger Blijdestijn <lutger.blijdestijn gmail.com> writes:
bearophile wrote:

 Andrei:
 
 This module won't compile in today's D, but not for a matter of
 principles; it's just a random limitation of the language. (It does work
 if you import from within a class or struct.) You can insert most
 declarations in a scope, so the ones you can't insert are just awkward
 exceptions, unless there's a good reason to actively disable them. Any
 code should work if you just wrap another scope around it.
 
 Walter and I call the above a "turtle feature", in allusion to the
 "turtles all the way down" meme. Walter wants to fix this, and similar
 limitations that act "unturtly". Imports inside a scope won't be visible
 outside that scope, and importing the same module from several different
 functions will come at no cost in compilation time.

You are allowed to import modules inside functions in Python too (there is a just a minor restriction), but I have never asked for this feature in D because this feature has a cost too. Putting all imports at the top of the module is more tidy, it allows the person that reads the code to find all the used imports very quickly. If they are spread in the module they become less easy to find, you need to use your editor/IDE to search for them. Bye, bearophile

Why would you have to find local imports? It's considered good practice to narrow scope of variables and put declarations as close as possible to point of use, yet you don't hunt for local variable declarations all the time. If an import is local, it is simply (supposedly) only of concern to that scope and relevant when doing work concerning whatever is in that scope. In effect this could as well lead to reducing to need to look for imports! Python is a bit different because there's an awful lot more going on when importing, with increased chances of bugs when not careful. Simply importing something more than once can introduce errors. Hopefully, that is less so with D. The only really tricky thing are module constructors (circular imports). But at this level, it's probably easier to use facilities of dmd to tell you what imports what.
Jun 11 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Lutger Blijdestijn:

It's considered good practice to narrow scope of variables and put declarations
as close as possible to point of use, yet you don't hunt for local variable
declarations all the time.<

I agree this turtle idea has some good sides too. But I want to stress that it's not among the first five things I think D has to change/improve. More important are tuple unpacking syntax sugar, named arguments, conditional attributes, better vector operations, etc. Bye, bearophile
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 7:20 AM, bearophile wrote:
 Lutger Blijdestijn:

 It's considered good practice to narrow scope of variables and put
 declarations as close as possible to point of use, yet you don't
 hunt for local variable declarations all the time.<

I agree this turtle idea has some good sides too. But I want to stress that it's not among the first five things I think D has to change/improve. More important are tuple unpacking syntax sugar, named arguments, conditional attributes, better vector operations, etc.

Again, there are two broad categories of changes: feature additions and removal of undue limitations. We favor doing the latter. Andrei
Jun 11 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 Again, there are two broad categories of changes: feature additions and 
 removal of undue limitations. We favor doing the latter.

I understand, but that's not always the best decision in this early stage of D life. There are also few little feature changes I have put in Bugzilla since lot of time. The more time passes, the less easy they are to apply. Bye, bearophile
Jun 11 2011
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/10/2011 6:15 PM, Andrej Mitrovic wrote:
 Wait, Walter wants to fix this? IIRC just a few days ago he made a
 post on how this would be a bad feature because it hides imports in
 arbitrary places.

I did?
Jun 10 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter:

 I did?

I don't remember you talking about this topic. But I don't want this feature, overall I think it will not improve the code. An amoeba is often free to move in every direction in 2D or more, while an insect has a rigid exoskeleton that constricts it to move only in few ways. But such limits allow the insect to run fast :-) Bye, bearophile
Jun 10 2011
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/10/11 8:51 PM, Andrej Mitrovic wrote:
 On 6/11/11, bearophile<bearophileHUGS lycos.com>  wrote:
 But I don't want this
 feature, overall I think it will not improve the code.

I've found someone that contradicts you: http://www.digitalmars.com/d/archives/digitalmars/D/Function-local_imports_109317.html

Wow. Andrei
Jun 10 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 I've found someone that contradicts you:
 http://www.digitalmars.com/d/archives/digitalmars/D/Function-local_imports_109317.html

Thank you. That person didn't have enough experience yet, it seems. More experienced Python programmers use local imports only in very uncommon situations, you see it from the lot of Python code in the standard library. So I despite its little advantage of local reasoning improvements I think it's far from the top of the list of the important things to desire, I think that currently design improvement efforts are better spent toward more generally useful features instead :-) Bye, bearophile
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 4:38 AM, bearophile wrote:
 Andrej Mitrovic:

 I've found someone that contradicts you:
 http://www.digitalmars.com/d/archives/digitalmars/D/Function-local_imports_109317.html

Thank you. That person didn't have enough experience yet, it seems. More experienced Python programmers use local imports only in very uncommon situations, you see it from the lot of Python code in the standard library. So I despite its little advantage of local reasoning improvements I think it's far from the top of the list of the important things to desire, I think that currently design improvement efforts are better spent toward more generally useful features instead :-) Bye, bearophile

I'm not very familiar with Python's module system. Is it very similar to D's? Thanks, Andrei
Jun 11 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 I'm not very familiar with Python's module system. Is it very similar to 
 D's?

If you take a look at the Python module system, you copy the first half of it, its more evident characteristics, ignoring its care for details and corner cases, and you remove its dynamic characteristics, you produce a kind of D module system :-) Python doesn't have the anti-hijacking feature, and it's more dynamic. Its package system is more refined than the primitive D package system (and it seems it's not easy to design right, because even the last versions of Python have modified a the its semantics of packages). In Python when you do "import foo" you import only the name "foo". This is probably one of the first things I've asked in D, and I am for it still, but most D programmers have not appreciated this idea, so I have stopped asking for it since lot of time. (S)ML language has a WAY more complex module system, but despite its advantages, I think D/Python module system is good enough and it's easy to learn to use. In the end on the surface if you know the Python module system it's easy to learn to use the D one, and the opposite too is true. I think the D package system needs to be improved, using more brain. This is another example of why D design development can't be stopped yet. Bye, bearophile
Jun 11 2011
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
Andrei Alexandrescu wrote:
 module my_module;

 void fun()
 {
      import std.random;
      return uniform(0, 100);
 }

 int gun()
 {
      import std.stdio;
      writeln(fun());
 }

 This module won't compile in today's D, but not for a matter of
 principles; it's just a random limitation of the language. (It does work
 if you import from within a class or struct.) You can insert most
 declarations in a scope, so the ones you can't insert are just awkward
 exceptions, unless there's a good reason to actively disable them. Any
 code should work if you just wrap another scope around it.

//void main(){ immutable a = b; immutable b = 1; int foo(int n){ if(n==1) return 1; return 1+bar(n); } int bar(int n){ if(n&1) return foo(3*n+1); return foo(n/2); } //} Will this be fixed too? Timon
Jun 13 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Will this be fixed too?

Mutually recursive inner functions are not so common, and there is a workaround, making one of them a delegate defined before. But what about this? auto foo()() out(result) { } body { return 0; } void main() { foo(); } test.d(1): Error: function test.foo!().foo post conditions are not supported if the return type is inferred test.d(7): Error: template instance test.foo!() error instantiating test.d(7): Error: forward reference to inferred return type of function call foo This is a common problem for my code, is it possible to fix (support) this? (In functional-style code auto return values are sometimes almost necessary). Bye, bearophile
Jun 13 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:isualt$hf2$1 digitalmars.com...
 Combining existing features towards new ends is in some ways more 
 difficult than language design because you play within a confined ground, 
 and I am a bit disappointed that a few posters have shown only contempt 
 for such an effort.

That analysis of the situation hinges on the steadfast notion that Flag is a great thing. I absolutely appreciate doing things in library instead of language when reasonable to do so. You don't see me asking for map/reduce or ranges to be built into the language, do you? What a lot of people *don't* like is this seemingly frequent pattern: 1. Andrei comes up with something he feels is a great idea (And you do have a lot of genuinely great ideas, don't get me wrong. Probably more than most of us, certainly including me.) 2. The idea is posted to the NG ostensibly for discussion. 3. Andrei shoots down every objection as being wrong, failing to understand the idea's greatness, or some meta-argument trump card like "X is the N-word of the programming world" is pulled out. 4. The proposed idea can't possibly have any significant flaws, so everyone else on the board is obviously in contempt of something more fundamental, in this case, the strategy of preferring library solutions over language additions. Just because some of us feel this one particular thing doesn't work well in library, does *not* imply we think new features are generally preferable as language additions. So please stop leaping to that conclusion.
Jun 10 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 12:36 AM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:isualt$hf2$1 digitalmars.com...
 Combining existing features towards new ends is in some ways more
 difficult than language design because you play within a confined ground,
 and I am a bit disappointed that a few posters have shown only contempt
 for such an effort.

That analysis of the situation hinges on the steadfast notion that Flag is a great thing.

Actually my point there was that we should be coy at this point about changing the language. Flag doesn't have much to do with it. It is clear to me that a language change would obviate Flag and would have additional advantages. The point is it would also have disadvantages.
 I absolutely appreciate doing things in library instead of language
 when reasonable to do so. You don't see me asking for map/reduce or
 ranges to be built into the language, do you? What a lot of people
 *don't* like is this seemingly frequent pattern:

 1. Andrei comes up with something he feels is a great idea (And you
 do have a lot of genuinely great ideas, don't get me wrong. Probably
 more than most of us, certainly including me.)

 2. The idea is posted to the NG ostensibly for discussion.

 3. Andrei shoots down every objection as being wrong, failing to
 understand the idea's greatness, or some meta-argument trump card
 like "X is the N-word of the programming world" is pulled out.

 4. The proposed idea can't possibly have any significant flaws, so
 everyone else on the board is obviously in contempt of something more
 fundamental, in this case, the strategy of preferring library
 solutions over language additions.

I thought what I was doing was to rationally discuss the proposal. Clearly I am in favor of it since I'm proposing it. But that doesn't mean I need to resort to eliciting emotional response, demeaning the counter-arguments, or discussing the competence or ulterior motives of the opponents.
 Just because some of us feel this one particular thing doesn't work well in
 library, does *not* imply we think new features are generally preferable as
 language additions. So please stop leaping to that conclusion.

Consider two statements: 1. "I dislike Flag. It looks ugly to me." 2. "I dislike Flag. Instead I want named arguments." There is little retort to (1) - it simply counts as a vote against. For (2) the course of action is to point out the liabilities of changing the language. Andrei
Jun 11 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-11 07:54:58 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Consider two statements:
 
 1. "I dislike Flag. It looks ugly to me."
 
 2. "I dislike Flag. Instead I want named arguments."
 
 There is little retort to (1) - it simply counts as a vote against. For 
 (2) the course of action is to point out the liabilities of changing 
 the language.

I'm actually not sure whether I want named arguments or not, but I'm quite sure I don't want to use Flag!"" in my code. I'd actually prefer a simple bool parameter to Flag!"". Currently, it looks like we have these possibilities: // definition // call with a constant void func(bool abc); -> func(true); enum Abc { no, yes } void func(Abc abc); -> func(Abc.yes); void func(Flag!"Abc" abc); -> func(Flag!"Abc".yes); -> func(yes!"Abc"); -> func(Yes.Abc); which then becomes this if you're using a boolean expression instead of a constant: // definition // call with an expression void func(bool abc); -> func(expression); enum Abc { no, yes } void func(Abc abc); -> func(expression ? Abc.yes : Abc.no); -> func(cast(Abc)expression); void func(Flag!"Abc" abc); -> func(expression ? Flag!"Abc".yes : Flag!"Abc".no); -> func(expression ? yes!"Abc" : no!"Abc"); -> func(expression ? Yes.Abc : No.Abc); -> func(cast(Flag!"Abc")expression); My take on this is that we shouldn't try to reinvent the boolean in the standard library. If you want to replace a bool with a two-option enum at some places for clarity, that's fine. But I wouldn't elevate that to a pattern meant to be used everywhere. And personally, I don't like the proliferation of yes/no enums: if you use an enum, value names should be more meaningful than a simple yes/no. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 8:16 AM, Michel Fortin wrote:
 On 2011-06-11 07:54:58 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

 2. "I dislike Flag. Instead I want named arguments."

 There is little retort to (1) - it simply counts as a vote against.
 For (2) the course of action is to point out the liabilities of
 changing the language.

I'm actually not sure whether I want named arguments or not, but I'm quite sure I don't want to use Flag!"" in my code. I'd actually prefer a simple bool parameter to Flag!"". Currently, it looks like we have these possibilities: // definition // call with a constant void func(bool abc); -> func(true);

The call entails simple data coupling as documented by Steve McConnell: you can pass any unstructured Boolean for any meaning of abc.
 enum Abc { no, yes }
 void func(Abc abc); -> func(Abc.yes);

To add the documentation effort: /** This is an argument for func. Refer to func below. */ enum Abc { no, /// you don't want func to do Abc yes /// you do want func to do Abc } /** This is func. Mind Abc defined above. */ void func(Abc abc); I think we agree this is rather awkward (I know because I wrote a fair amount of such). So we have the advantage of a nice call syntax and the disadvantage of verbose definition and documentation.
 void func(Flag!"Abc" abc); -> func(Flag!"Abc".yes);
 -> func(yes!"Abc");
 -> func(Yes.Abc);

 which then becomes this if you're using a boolean expression instead of
 a constant:

Aha! This reasoning is flawed as I'll explain below.
 // definition // call with an expression

 void func(bool abc); -> func(expression);

 enum Abc { no, yes }
 void func(Abc abc); -> func(expression ? Abc.yes : Abc.no);
 -> func(cast(Abc)expression);

 void func(Flag!"Abc" abc); -> func(expression ? Flag!"Abc".yes :
 Flag!"Abc".no);
 -> func(expression ? yes!"Abc" : no!"Abc");
 -> func(expression ? Yes.Abc : No.Abc);
 -> func(cast(Flag!"Abc")expression);

 My take on this is that we shouldn't try to reinvent the boolean in the
 standard library.

I think this characterization is wrong. Let me replace the meaningless Abc with an actual example, e.g. OpenRight in std.algorithm. OpenRight is not a Boolean. Its *representation* is Boolean. It is categorical data with two categories. You can represent it with an unstructured Boolean the same way you can represent an automaton state with an unstructured integer or temperature with an unstructured double, but then you'd have the disadvantages that dimensional analysis libraries are solving. For representing categorical data with small sets, programming languages use enumerated types. This is because in a small set you can actually give name each element. That way you have a separate type for the categorical data so you can enjoy good type checking. The mistake I believe you are making is the conflation of a categorical data with two categories with an unstructured Boolean. By making that conflation you lose the advantages of good typechecking in one fell swoop. (But not all categorical data is a small set, and consequently enumerated types are insufficient. Consider e.g. the notion of a user id. People routinely use integers for that, and suffer endless consequences because of bugs caused by unstructured integers posing as user IDs. I have seen instances of such bugs in several codebases in different languages.) As a direct consequence, it is *wrong* to desire to pass an unstructured Boolean expression in lieu of OpenRight. So it is *good* that you can't. What you *should* be doing is to define an OpenRight value in the first place and use it, or construct it in place with "expr ? OpenRight.yes : OpenRight.no", with the advantage that the conversion intent is explicit and visible.
 If you want to replace a bool with a two-option enum
 at some places for clarity, that's fine. But I wouldn't elevate that to
 a pattern meant to be used everywhere. And personally, I don't like the
 proliferation of yes/no enums: if you use an enum, value names should be
 more meaningful than a simple yes/no.

I think you'd be entirely wrong to make this distinction. There's zero, one, and many. Not zero, one, two, and many. Andrei
Jun 11 2011
next sibling parent David Nadlinger <see klickverbot.at> writes:
On 6/11/11 3:56 PM, Andrei Alexandrescu wrote:
 To add the documentation effort:

 /**
 This is an argument for func. Refer to func below.
 */
 enum Abc {
 no, /// you don't want func to do Abc
 yes /// you do want func to do Abc
 }

 /**
 This is func. Mind Abc defined above.
 */
 void func(Abc abc);

 I think we agree this is rather awkward (I know because I wrote a fair
 amount of such).

 So we have the advantage of a nice call syntax and the disadvantage of
 verbose definition and documentation.

So what? Library code is typically written once, and used often. Also, what's wrong with the followig (maybe there is really an issue with it, didn't run it through DDoc): --- /** * This is func. * * Params: * abc = Abc.yes to destroy the world, Abc.no to leave it intact. */ void func(Abc abc) {} /// Ditto. enum Abc : bool { no, yes } --- David
Jun 11 2011
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-11 09:56:28 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 6/11/11 8:16 AM, Michel Fortin wrote:
 On 2011-06-11 07:54:58 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 
 Consider two statements:
 
 1. "I dislike Flag. It looks ugly to me."
 
 2. "I dislike Flag. Instead I want named arguments."
 
 There is little retort to (1) - it simply counts as a vote against.
 For (2) the course of action is to point out the liabilities of
 changing the language.

I'm actually not sure whether I want named arguments or not, but I'm quite sure I don't want to use Flag!"" in my code. I'd actually prefer a simple bool parameter to Flag!"". Currently, it looks like we have these possibilities: // definition // call with a constant void func(bool abc); -> func(true);

The call entails simple data coupling as documented by Steve McConnell: you can pass any unstructured Boolean for any meaning of abc.

Which is often useful if the value is conditional to a boolean expression. The only lacking thing is the parameter name which would make things clear to the reader. Structured data is useful only if you pass it around; if you use it only once as a function parameter and nowhere else, then it just gets in the way. If your argument was that structured data is always preferred to unstructured data, I disagree.
 enum Abc { no, yes }
 void func(Abc abc); -> func(Abc.yes);

To add the documentation effort: /** This is an argument for func. Refer to func below. */ enum Abc { no, /// you don't want func to do Abc yes /// you do want func to do Abc } /** This is func. Mind Abc defined above. */ void func(Abc abc); I think we agree this is rather awkward (I know because I wrote a fair amount of such). So we have the advantage of a nice call syntax and the disadvantage of verbose definition and documentation.

Yes, and I think most of the time this should be a bool. Or to be precise: if it's not worth documenting separately, especially if it's used just once as a flag to a specific function, and if you don't expect it to extend to more than yes/no, then it should be a bool.
 void func(Flag!"Abc" abc); -> func(Flag!"Abc".yes);
 -> func(yes!"Abc");
 -> func(Yes.Abc);
 
 which then becomes this if you're using a boolean expression instead of
 a constant:

Aha! This reasoning is flawed as I'll explain below.
 // definition // call with an expression
 
 void func(bool abc); -> func(expression);
 
 enum Abc { no, yes }
 void func(Abc abc); -> func(expression ? Abc.yes : Abc.no);
 -> func(cast(Abc)expression);
 
 void func(Flag!"Abc" abc); -> func(expression ? Flag!"Abc".yes :
 Flag!"Abc".no);
 -> func(expression ? yes!"Abc" : no!"Abc");
 -> func(expression ? Yes.Abc : No.Abc);
 -> func(cast(Flag!"Abc")expression);
 
 My take on this is that we shouldn't try to reinvent the boolean in the
 standard library.

I think this characterization is wrong. Let me replace the meaningless Abc with an actual example, e.g. OpenRight in std.algorithm. OpenRight is not a Boolean. Its *representation* is Boolean. It is categorical data with two categories. You can represent it with an unstructured Boolean the same way you can represent an automaton state with an unstructured integer or temperature with an unstructured double, but then you'd have the disadvantages that dimensional analysis libraries are solving. For representing categorical data with small sets, programming languages use enumerated types. This is because in a small set you can actually give name each element. That way you have a separate type for the categorical data so you can enjoy good type checking. The mistake I believe you are making is the conflation of a categorical data with two categories with an unstructured Boolean. By making that conflation you lose the advantages of good typechecking in one fell swoop.

I think you're misinterpreting. I don't like yes/no enums because I don't find the value names meaningful, but I'm perfectly fine with two-element enums if they are properly named.
 (But not all categorical data is a small set, and consequently 
 enumerated types are insufficient. Consider e.g. the notion of a user 
 id. People routinely use integers for that, and suffer endless 
 consequences because of bugs caused by unstructured integers posing as 
 user IDs. I have seen instances of such bugs in several codebases in 
 different languages.)

I totally agree with making specific types to avoid mixing unrelated things, as long as it's reasonable. You wouldn't argue for a UserId type if values of this type weren't passed around.
 As a direct consequence, it is *wrong* to desire to pass an 
 unstructured Boolean expression in lieu of OpenRight. So it is *good* 
 that you can't. What you *should* be doing is to define an OpenRight 
 value in the first place and use it, or construct it in place with 
 "expr ? OpenRight.yes : OpenRight.no", with the advantage that the 
 conversion intent is explicit and visible.

But boundaries can be open or closed on the right, but also on the left. Unfortunately, because you choose to call the enum OpenRight, it can only be used on the right, and nowhere else. What you're doing with OpenRight, and more generally with Flag!"", is narrowing excessively the category to the point where it can be used at one place and one place only: as a specific parameter to a specific function. If you had another parameter for the left side, you'd create an OpenLeft enum with exactly the same choices. I doubt this kind of categorization has any advantage. Actually, I think the advantage you seek has nothing to do with categorization and much more to do with a desire to see those parameter names appear at the call site. You're actually using over-categorization to achieve that, and with Flag!"" you're going to make this systematic. Sorry, I can't approve.
 If you want to replace a bool with a two-option enum
 at some places for clarity, that's fine. But I wouldn't elevate that to
 a pattern meant to be used everywhere. And personally, I don't like the
 proliferation of yes/no enums: if you use an enum, value names should be
 more meaningful than a simple yes/no.

I think you'd be entirely wrong to make this distinction. There's zero, one, and many. Not zero, one, two, and many.

No idea what you mean there. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 10:40 AM, Michel Fortin wrote:
 On 2011-06-11 09:56:28 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 For representing categorical data with small sets, programming
 languages use enumerated types. This is because in a small set you can
 actually give name each element. That way you have a separate type for
 the categorical data so you can enjoy good type checking. The mistake
 I believe you are making is the conflation of a categorical data with
 two categories with an unstructured Boolean. By making that conflation
 you lose the advantages of good typechecking in one fell swoop.

I think you're misinterpreting. I don't like yes/no enums because I don't find the value names meaningful, but I'm perfectly fine with two-element enums if they are properly named.

What is meaningless about OpenRight.yes?
 (But not all categorical data is a small set, and consequently
 enumerated types are insufficient. Consider e.g. the notion of a user
 id. People routinely use integers for that, and suffer endless
 consequences because of bugs caused by unstructured integers posing as
 user IDs. I have seen instances of such bugs in several codebases in
 different languages.)

I totally agree with making specific types to avoid mixing unrelated things, as long as it's reasonable. You wouldn't argue for a UserId type if values of this type weren't passed around.

The problem is the definition of "reasonable" is loose. For all I can tell we agree, it's just we have different notions of what's reasonable.
 But boundaries can be open or closed on the right, but also on the left.
 Unfortunately, because you choose to call the enum OpenRight, it can
 only be used on the right, and nowhere else.

But this is intentional. If I wanted something more general, I would have used something more general! What are you saying here?
 What you're doing with OpenRight, and more generally with Flag!"", is
 narrowing excessively the category to the point where it can be used at
 one place and one place only: as a specific parameter to a specific
 function. If you had another parameter for the left side, you'd create
 an OpenLeft enum with exactly the same choices. I doubt this kind of
 categorization has any advantage.

In fact, no. The same Flag instantiation can be used with distinct functions. Its advantage is that you don't need to go out of your way and define it. It's a sort of a lambda, a literal for a categorical value.
 Actually, I think the advantage you seek has nothing to do with
 categorization and much more to do with a desire to see those parameter
 names appear at the call site. You're actually using over-categorization
 to achieve that, and with Flag!"" you're going to make this systematic.
 Sorry, I can't approve.

I think it's best to discuss the pros and cons of the proposal than the proposer's desires. Yes, clarifying the intent at the call site is a good thing. And yes, systematization can be good. Named parameters would be one way to go about it, and categorization would be another. If you characterize the approach as *over* categorization, I'm interested in your justification of that qualification.
 If you want to replace a bool with a two-option enum
 at some places for clarity, that's fine. But I wouldn't elevate that to
 a pattern meant to be used everywhere. And personally, I don't like the
 proliferation of yes/no enums: if you use an enum, value names should be
 more meaningful than a simple yes/no.

I think you'd be entirely wrong to make this distinction. There's zero, one, and many. Not zero, one, two, and many.

No idea what you mean there.

Sets with zero and one elements have distinctive properties compared to sets of more than one element. Sets with two elements don't. Andrei
Jun 11 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-11 12:01:33 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 6/11/11 10:40 AM, Michel Fortin wrote:
 On 2011-06-11 09:56:28 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 For representing categorical data with small sets, programming
 languages use enumerated types. This is because in a small set you can
 actually give name each element. That way you have a separate type for
 the categorical data so you can enjoy good type checking. The mistake
 I believe you are making is the conflation of a categorical data with
 two categories with an unstructured Boolean. By making that conflation
 you lose the advantages of good typechecking in one fell swoop.

I think you're misinterpreting. I don't like yes/no enums because I don't find the value names meaningful, but I'm perfectly fine with two-element enums if they are properly named.

What is meaningless about OpenRight.yes?

Choosing between "yes" and "no" is not meaningful. I'd rather choose between "open" and "closed". Of course you'd have to pick a more fitting name for the enum, preferably one that could work for all bounds, not just the right one to make the category more useful. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 11:56 AM, Michel Fortin wrote:
 On 2011-06-11 12:01:33 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 On 6/11/11 10:40 AM, Michel Fortin wrote:
 On 2011-06-11 09:56:28 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 For representing categorical data with small sets, programming
 languages use enumerated types. This is because in a small set you can
 actually give name each element. That way you have a separate type for
 the categorical data so you can enjoy good type checking. The mistake
 I believe you are making is the conflation of a categorical data with
 two categories with an unstructured Boolean. By making that conflation
 you lose the advantages of good typechecking in one fell swoop.

I think you're misinterpreting. I don't like yes/no enums because I don't find the value names meaningful, but I'm perfectly fine with two-element enums if they are properly named.

What is meaningless about OpenRight.yes?

Choosing between "yes" and "no" is not meaningful. I'd rather choose between "open" and "closed".

I don't see how "OpenRight.yes" is meaningless and "Openness.right" is meaningful.
 Of course you'd have to pick a more fitting
 name for the enum,

Name one.
 preferably one that could work for all bounds, not
 just the right one to make the category more useful.

Again, the charter of that particular category is only "open to the right". Anyway, that was the first thing "grep yes std/*" found. Let's see the next one: /** Specifies whether the output of certain algorithm is desired in sorted format. */ enum SortOutput { no, /// Don't sort output yes, /// Sort output } This already is very unpleasant because "certain" is as imprecise as it gets. Plus one for Flag, I hope you agree. Alright, so we have void topNIndex( alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index, SortOutput sorted = SortOutput.no); With Flag in tow, you'd delete SortOutput and you'd replace the definition with: void topNIndex( alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index, Flag!"sortOutput" sorted = No.sortOutput); Call: auto a = [ 1, 2, 3 ]; topNIndex(a, Yes.sortOutput); I understand you find the above meaningless and would advocate using a bool, which means: topNIndex(a, true); which would have even me running to the manual, and I wrote the darn thing. With named parameters, we'd have something along the lines of: topNIndex(a, sortOutput : true); which is nice, but not present in the language (and I can tell after talking to Walter it won't be anytime soon). With your choice of meaningful/less, you'd have something like: enum HowToOutput { unsorted, sorted } topNIndex(a, HowToOutput.sorted); which is pretty much the same thing as yes/no, just more convoluted and less systematic. I mean you can't impose to yourself to choose any names except "yes" and "no" on account of them being meaningless. Andrei
Jun 11 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-11 13:08:48 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 With named parameters, we'd have something along the lines of:
 
 topNIndex(a, sortOutput : true);
 
 which is nice, but not present in the language (and I can tell after 
 talking to Walter it won't be anytime soon).

The funny thing is that named arguments are not that difficult to implement as long as you don't allow reordering. Much easier than const(Object)ref actually. <https://github.com/michelf/dmd/commit/673bae4982ff18a3d216bc1578f50d40f4d26d7a> Took me less time than what I took arguing about Flag!"". -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 1:59 PM, Michel Fortin wrote:
 On 2011-06-11 13:08:48 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 With named parameters, we'd have something along the lines of:

 topNIndex(a, sortOutput : true);

 which is nice, but not present in the language (and I can tell after
 talking to Walter it won't be anytime soon).

The funny thing is that named arguments are not that difficult to implement as long as you don't allow reordering. Much easier than const(Object)ref actually. <https://github.com/michelf/dmd/commit/673bae4982ff18a3d216bc1578f50d40f4d26d7a> Took me less time than what I took arguing about Flag!"".

Love the attitude!! Let's see what Don and Walter think. Andrei
Jun 11 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/11/2011 12:58 PM, Andrei Alexandrescu wrote:
 On 6/11/11 1:59 PM, Michel Fortin wrote:
 On 2011-06-11 13:08:48 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 With named parameters, we'd have something along the lines of:

 topNIndex(a, sortOutput : true);

 which is nice, but not present in the language (and I can tell after
 talking to Walter it won't be anytime soon).

The funny thing is that named arguments are not that difficult to implement as long as you don't allow reordering. Much easier than const(Object)ref actually. <https://github.com/michelf/dmd/commit/673bae4982ff18a3d216bc1578f50d40f4d26d7a> Took me less time than what I took arguing about Flag!"".

Love the attitude!! Let's see what Don and Walter think.

I think it's clever and insightful how Michel's solution is implemented. It does not allow, however, for named arguments to be not in the same positions as unnamed ones. In other words, unlike struct field initializations, named arguments cannot appear in any order. I think people will find it an odd difference.
Jun 11 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/11/2011 10:05 PM, Walter Bright wrote:
 On 6/11/2011 12:58 PM, Andrei Alexandrescu wrote:
 On 6/11/11 1:59 PM, Michel Fortin wrote:
 On 2011-06-11 13:08:48 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 With named parameters, we'd have something along the lines of:

 topNIndex(a, sortOutput : true);

 which is nice, but not present in the language (and I can tell after
 talking to Walter it won't be anytime soon).

The funny thing is that named arguments are not that difficult to implement as long as you don't allow reordering. Much easier than const(Object)ref actually. <https://github.com/michelf/dmd/commit/673bae4982ff18a3d216bc1578f50d40f4d26d7a> Took me less time than what I took arguing about Flag!"".

Love the attitude!! Let's see what Don and Walter think.

I think it's clever and insightful how Michel's solution is implemented. It does not allow, however, for named arguments to be not in the same positions as unnamed ones. In other words, unlike struct field initializations, named arguments cannot appear in any order. I think people will find it an odd difference.

If we all get convinced that named parameters are worth it, I'm convinced Michel would be sufficiently motivated to address this limitation. I personally am lukewarm regarding the feature but I think many people would find it quite convenient. Andrei
Jun 11 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the 
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
  */
 enum SortOutput {
     no,  /// Don't sort output
     yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as it 
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear. Also, since you're in favor of Flag, I think you'd agree with me that the doc comments on the "no" and "yes" values are unnecessary and can be ditched. Which makes the whole idiom this: enum SortOutput { no, yes } I hadn't noticed this before, but now that I'm actually looking directly at that, I don't see how that can be considered "boilerplate", or at least enough boilerplate to be worth having a utility template, adding Flag!"..." to function signatures in the code and documentation, and the inconsistency in changing the user's syntax away from how people expect to use an enum. And not only that, but all for the sake of a scenario that you've already argued is only rarely encountered. It's a clever use of templates, sure, but it's a little too clever for it's own good.
Jun 11 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
   */
 enum SortOutput {
      no,  /// Don't sort output
      yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2
 Also, since you're in favor of Flag, I think you'd agree with me that the
 doc comments on the "no" and "yes" values are unnecessary and can be
 ditched. Which makes the whole idiom this:

 enum SortOutput { no, yes }

This exact kind of argument has been made in 1995 in favor of STL algorithms that require defining a struct outside the current context. The cost of adding one extra symbol turned out to be a fair amount more unpleasant than it was initially though. Assessing that the boilerplate in this case is one line would be missing that important aspect. Andrei
Jun 11 2011
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 06/11/2011 10:45 PM, Jonathan M Davis wrote:
 Yes, though there is a distinct difference between having to create a functor
 elswhere to just to call an STL function and creating an extra enum next to
 your function definition for one of its parameters. The parameter issue is far
 smaller IMHO.

Absolutely. The proposed solution is also much smaller than e.g. lambda libraries and ultimately the language feature. Andrei
Jun 11 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:it1c0f$1uup$1 digitalmars.com...
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
   */
 enum SortOutput {
      no,  /// Don't sort output
      yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2

Not that I consider quibbling over small English wording differences a major thing, but I fail to see how: "Specifies whether the output of an algorithm is desired in sorted format." is significantly different from: "Specifies whether the output of certain algorithms are desired in sorted format." In either case, I don't see anything problematically imprecise.
Jun 12 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/12/11 1:45 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it1c0f$1uup$1 digitalmars.com...
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>   wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
    */
 enum SortOutput {
       no,  /// Don't sort output
       yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2

Not that I consider quibbling over small English wording differences a major thing, but I fail to see how: "Specifies whether the output of an algorithm is desired in sorted format." is significantly different from: "Specifies whether the output of certain algorithms are desired in sorted format." In either case, I don't see anything problematically imprecise.

Still means I need to jump back and forth in the documentation. Andrei
Jun 12 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:it32j8$2gfq$1 digitalmars.com...
 On 6/12/11 1:45 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it1c0f$1uup$1 digitalmars.com...
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>   wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
    */
 enum SortOutput {
       no,  /// Don't sort output
       yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as 
 it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2

Not that I consider quibbling over small English wording differences a major thing, but I fail to see how: "Specifies whether the output of an algorithm is desired in sorted format." is significantly different from: "Specifies whether the output of certain algorithms are desired in sorted format." In either case, I don't see anything problematically imprecise.

Still means I need to jump back and forth in the documentation.

And you don't like the "///ditto" suggestion for handling that?
Jun 12 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/12/11 2:19 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it32j8$2gfq$1 digitalmars.com...
 On 6/12/11 1:45 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>   wrote in message
 news:it1c0f$1uup$1 digitalmars.com...
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>    wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
     */
 enum SortOutput {
        no,  /// Don't sort output
        yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as
 it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2

Not that I consider quibbling over small English wording differences a major thing, but I fail to see how: "Specifies whether the output of an algorithm is desired in sorted format." is significantly different from: "Specifies whether the output of certain algorithms are desired in sorted format." In either case, I don't see anything problematically imprecise.

Still means I need to jump back and forth in the documentation.

And you don't like the "///ditto" suggestion for handling that?

That actually does help, but not for enums used by more than one function. The other issues remain too. Andrei
Jun 12 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:it3ne2$1g2f$1 digitalmars.com...
 On 6/12/11 2:19 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it32j8$2gfq$1 digitalmars.com...
 On 6/12/11 1:45 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>   wrote in message
 news:it1c0f$1uup$1 digitalmars.com...
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>    wrote in 
 message
 news:it07ni$1pvj$1 digitalmars.com...
 Anyway, that was the first thing "grep yes std/*" found. Let's see 
 the
 next one:

 /**
 Specifies whether the output of certain algorithm is desired in 
 sorted
 format.
     */
 enum SortOutput {
        no,  /// Don't sort output
        yes, /// Sort output
 }

 This already is very unpleasant because "certain" is as imprecise as
 it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2

Not that I consider quibbling over small English wording differences a major thing, but I fail to see how: "Specifies whether the output of an algorithm is desired in sorted format." is significantly different from: "Specifies whether the output of certain algorithms are desired in sorted format." In either case, I don't see anything problematically imprecise.

Still means I need to jump back and forth in the documentation.

And you don't like the "///ditto" suggestion for handling that?

That actually does help, but not for enums used by more than one function. The other issues remain too.

I would think that an enum used by more than one function *should* be listed separately.
Jun 13 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/13/11 4:02 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it3ne2$1g2f$1 digitalmars.com...
 That actually does help, but not for enums used by more than one function.
 The other issues remain too.

I would think that an enum used by more than one function *should* be listed separately.

Actually, not necessarily, if the definition is self explanatory. By the same argument a named argument with the same name and meaning in several functions doesn't necessarily have to be defined separately. Andrei
Jun 13 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
 On 6/13/11 4:02 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it3ne2$1g2f$1 digitalmars.com...
 That actually does help, but not for enums used by more than one function.
 The other issues remain too.

I would think that an enum used by more than one function *should* be listed separately.

Actually, not necessarily, if the definition is self explanatory. By the same argument a named argument with the same name and meaning in several functions doesn't necessarily have to be defined separately. Andrei

What about just not documenting the enum itself? This elegantly resolves the 'certain' vs. 'an' debate too :o). Timon
Jun 13 2011
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On 2011-06-11 20:27, Andrei Alexandrescu wrote:
 On 06/11/2011 03:52 PM, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:it07ni$1pvj$1 digitalmars.com...
 
 Anyway, that was the first thing "grep yes std/*" found. Let's see the
 next one:
 
 /**
 Specifies whether the output of certain algorithm is desired in sorted
 format.
 
   */
 
 enum SortOutput {
 
      no,  /// Don't sort output
      yes, /// Sort output
 
 }
 
 This already is very unpleasant because "certain" is as imprecise as it
 gets. Plus one for Flag, I hope you agree.

Flag -= 1 s/output of certain algorithm/output of an algorithm/ += 1 That one-word doc change makes it all perfectly clear.

Not at all. The typo in the original text must have confused you: it should be "certain algorithms" because SortOutput is used in four distinct algorithms (one of which has two overloads). Grep std/algorithm.d. Flag += 2
 Also, since you're in favor of Flag, I think you'd agree with me that the
 doc comments on the "no" and "yes" values are unnecessary and can be
 ditched. Which makes the whole idiom this:
 
 enum SortOutput { no, yes }

This exact kind of argument has been made in 1995 in favor of STL algorithms that require defining a struct outside the current context. The cost of adding one extra symbol turned out to be a fair amount more unpleasant than it was initially though. Assessing that the boilerplate in this case is one line would be missing that important aspect.

Yes, though there is a distinct difference between having to create a functor elswhere to just to call an STL function and creating an extra enum next to your function definition for one of its parameters. The parameter issue is far smaller IMHO. It only comes up when defining functions, and particularly if we created a mixin for creating such an enum, the overhead would be fairly minimal - certainly far less than creating a functor for every call to an STL algorithm function (which pratically destroys the usefulness of the STL's algorithms for most people). So, I don't think that the cost involved is altogether comparable. However, you do bring up a very valid point. Flag definitely lowers the bar for the usage of such enums. Ultimately, my main concern with using Flag like this is the error messages. Given the templates involved, I'd expect them to be pretty bad. D's template error messages are certainly better than C++'s (primarily thanks to template constraints), but they're still pretty bad - especially for newbies - and this particular use case effectively is simplifying the library developer's life slightly at the cost of nastier error messages for everyone who mistypes one of these enums. So, we save pain in one area and move it over to another which arguably has a higher impact. And I'm just not sure whether that's worth it or not. The fact that you've gotten to Yes.EnumName and eliminated all of the obvious template stuff from the user's perspective makes the code much cleaner, and it's fine as long as they don't have any typos, but the difference between EnumName.yes and Yes.EnumName for the user is pretty much nonexistant except for the fact that Yes.EnumName will have worse error messages. So, from the user's perspective, the situation is worse. I don't know. I think that this proposal has reached the point where it might be reasonable to include it, but I just don't know if the gain in development is worth the pain for everyone who uses the functions which have Flag enums. If the error messages weren't worse, then it wouldn't be a problem, but as soon as you include templates, the error messages are pretty much always significantly worse. If there were a significant gain from this proposal, then I'd say that it would be worth it, but the gain seems pretty minor to me. So, I just don't know. - Jonathan M Davis
Jun 11 2011
parent "Nick Sabalausky" <a a.a> writes:
"Jonathan M Davis" <jmdavisProg gmx.com> wrote in message 
news:mailman.841.1307850316.14074.digitalmars-d puremagic.com...
 but the
 difference between EnumName.yes and Yes.EnumName for the user is pretty 
 much
 nonexistant except for the fact that Yes.EnumName will have worse error
 messages.

It also creates an awkward inconsistency. Most enums are X.Y, but then callint certain functions it's Y.X
Jun 12 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
so:

 Quite contrary i think it is pretty much spot on, if it is not but just  
 its representation is boolean so is every other usage of boolean.

This is an unusual teacher that use functional languages, the blog post is about booleans and related matters: http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/ (Often I don't agree with this author, but I try to read some of his posts.) Bye, bearophile
Jun 12 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/12/11 7:26 AM, so wrote:
 My take on this is that we shouldn't try to reinvent the boolean in the
 standard library.

I think this characterization is wrong. Let me replace the meaningless Abc with an actual example, e.g. OpenRight in std.algorithm. OpenRight is not a Boolean. Its *representation* is Boolean. It is categorical data with two categories. You can represent it with an unstructured Boolean the same way you can represent an automaton state with an unstructured integer or temperature with an unstructured double, but then you'd have the disadvantages that dimensional analysis libraries are solving.

Quite contrary i think it is pretty much spot on, if it is not but just its representation is boolean so is every other usage of boolean. The only reason we use an enum instead of simple bool is self documentation "fun(OpenRight.yes)". You simply can't deny the named arguments solve not only this particular issue but the entire area nicely "fun(openRight:true, width:4, height:3, depth:5)".

Never did. Andrei
Jun 12 2011
prev sibling next sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 6/11/11 1:54 PM, Andrei Alexandrescu wrote:
 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

 2. "I dislike Flag. Instead I want named arguments."

 There is little retort to (1) - it simply counts as a vote against. For
 (2) the course of action is to point out the liabilities of changing the
 language.

*And*, at least for me, still count it as an (informal) vote against Flag. You wrote about »The point is it [named arguments] would also have disadvantages«, but at the same time, you seem to ignore that using a non-obvious construct all over the standard library adds to perceived the »language complexity« (from the user's perspective) just as well, even more so if opDispatch or other »hacks« are used to beautify the implementation. Yes, I do think named parameters would be a step forward and we should definitely look into adding them to D. But independently, I don't think that reinventing bool in Phobos is a good idea. How would you explain somebody new to D that, while usually it's »Something.property«, you have to write »Yes.foo« instead of »Foo.yes«? Also, there is the issue of error messages: --- void foo(Flag!"bar" flag) {} void main() { foo(No.baz); } --- leads to --- Error: function foo (Flag flag) is not callable using argument types (Flag) Error: cannot implicitly convert expression (opDispatch()) of type Flag to Flag --- I don't know about you, but I think this is not quite an acceptable error message for mistyping a single character while trying to pass a boolean parameter to some standard library function. David
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 9:08 AM, David Nadlinger wrote:
 On 6/11/11 1:54 PM, Andrei Alexandrescu wrote:
 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

 2. "I dislike Flag. Instead I want named arguments."

 There is little retort to (1) - it simply counts as a vote against. For
 (2) the course of action is to point out the liabilities of changing the
 language.

*And*, at least for me, still count it as an (informal) vote against Flag.

Of course it does, but the point is there are arguments that might convince the person.
 You wrote about »The point is it [named arguments] would also have
 disadvantages«, but at the same time, you seem to ignore that using a
 non-obvious construct all over the standard library adds to perceived
 the »language complexity« (from the user's perspective) just as well,
 even more so if opDispatch or other »hacks« are used to beautify the
 implementation.

I agree that implementation complexity has a cost. That would be justified if the idiom becomes commonly used outside the library.
 Yes, I do think named parameters would be a step forward and we should
 definitely look into adding them to D. But independently, I don't think
 that reinventing bool in Phobos is a good idea.

You may want to refer to my answer to Michel. Andrei
Jun 11 2011
parent Ben Grabham <Evil.Nebster gmail.com> writes:
On 11/06/11 15:28, Andrei Alexandrescu wrote:
 On 6/11/11 9:08 AM, David Nadlinger wrote:
 On 6/11/11 1:54 PM, Andrei Alexandrescu wrote:
 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

 2. "I dislike Flag. Instead I want named arguments."

 There is little retort to (1) - it simply counts as a vote against. For
 (2) the course of action is to point out the liabilities of changing the
 language.

*And*, at least for me, still count it as an (informal) vote against Flag.

Of course it does, but the point is there are arguments that might convince the person.
 You wrote about »The point is it [named arguments] would also have
 disadvantages«, but at the same time, you seem to ignore that using a
 non-obvious construct all over the standard library adds to perceived
 the »language complexity« (from the user's perspective) just as well,
 even more so if opDispatch or other »hacks« are used to beautify the
 implementation.

I agree that implementation complexity has a cost. That would be justified if the idiom becomes commonly used outside the library.
 Yes, I do think named parameters would be a step forward and we should
 definitely look into adding them to D. But independently, I don't think
 that reinventing bool in Phobos is a good idea.

You may want to refer to my answer to Michel. Andrei

Hey, Don't know whether I can vote but I looked through it and I prefer using booleans over this. This just doesn't look very nice to me and if you *really* wanted to use this in a program, you could just use an enum but I don't see why flags is good (even after reading through all your counter-arguments). Nebster
Jun 11 2011
prev sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 11/06/2011 12:54, Andrei Alexandrescu wrote:
 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

This statement holds true for me.
 2. "I dislike Flag. Instead I want named arguments."

This one is perhaps true. I've never needed named arguments.
 There is little retort to (1) - it simply counts as a vote against. For
 (2) the course of action is to point out the liabilities of changing the
 language.

 Andrei

So I had an idea. ---- struct Flag { static bool opDispatch(string n)() { static if (n[0..2] == "no") { return false; } else { return true; } } } void myFunc(bool foo, bool bar) { } void main() { myFunc(Flag.foo, Flag.noBar); } ---- * No ugly templates * Self documenting * No overhead (dmd can inline it to myFunc(true, false)) * Caller decides if they want it -- Robert http://octarineparrot.com/
Jun 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/11/11 2:12 PM, Robert Clipsham wrote:
 On 11/06/2011 12:54, Andrei Alexandrescu wrote:
 Consider two statements:

 1. "I dislike Flag. It looks ugly to me."

This statement holds true for me.
 2. "I dislike Flag. Instead I want named arguments."

This one is perhaps true. I've never needed named arguments.
 There is little retort to (1) - it simply counts as a vote against. For
 (2) the course of action is to point out the liabilities of changing the
 language.

 Andrei

So I had an idea. ---- struct Flag { static bool opDispatch(string n)() { static if (n[0..2] == "no") { return false; } else { return true; } } } void myFunc(bool foo, bool bar) { } void main() { myFunc(Flag.foo, Flag.noBar); } ---- * No ugly templates * Self documenting * No overhead (dmd can inline it to myFunc(true, false)) * Caller decides if they want it

// Generate document in nook format generatePdf("doc.pdf", Flag.nook); Andrei
Jun 11 2011
parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 11/06/2011 20:59, Andrei Alexandrescu wrote:
 On 6/11/11 2:12 PM, Robert Clipsham wrote:
 ....
 * No ugly templates
 * Self documenting
 * No overhead (dmd can inline it to myFunc(true, false))
 * Caller decides if they want it

// Generate document in nook format generatePdf("doc.pdf", Flag.nook); Andrei

I'd call this a documentation issue. It's obvious you're passing true to the function. Of course, if you want to mitigate this somewhat, something like this could work: struct FuncFlag(alias func) { // See code from above, but use typeof(&func).stringof to get // a list of parameter names and make sure the passed name is valid // of course, you can't check position, but the only way to get // around that is named parameters or some sort of compiler support } alias FuncFlag!generatePdf PdfFlag; // This now fails to compile generatePdf("doc.pdf", PdfFlag.nook); -- Robert http://octarineparrot.com/
Jun 11 2011
parent Robert Clipsham <robert octarineparrot.com> writes:
On 11/06/2011 21:31, Robert Clipsham wrote:
 On 11/06/2011 20:59, Andrei Alexandrescu wrote:
 On 6/11/11 2:12 PM, Robert Clipsham wrote:
 ....
 * No ugly templates
 * Self documenting
 * No overhead (dmd can inline it to myFunc(true, false))
 * Caller decides if they want it

// Generate document in nook format generatePdf("doc.pdf", Flag.nook); Andrei

I'd call this a documentation issue. It's obvious you're passing true to the function. Of course, if you want to mitigate this somewhat, something like this could work: struct FuncFlag(alias func) { // See code from above, but use typeof(&func).stringof to get // a list of parameter names and make sure the passed name is valid // of course, you can't check position, but the only way to get // around that is named parameters or some sort of compiler support } alias FuncFlag!generatePdf PdfFlag; // This now fails to compile generatePdf("doc.pdf", PdfFlag.nook);

<idea> You can actually check the order! Add in a counter to FuncFlag, and each time opDispatch is called increment it. You can use this to check the position. The obvious downside is optional parameters, where the counter will be incorrect unless you reset it. </idea> -- Robert http://octarineparrot.com/
Jun 11 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On 2011-06-10 16:46, Andrei Alexandrescu wrote:
 On 6/10/11 6:26 PM, bearophile wrote:
 Andrei:
 That's good evidence that introducing named parameters would be
 quite involved.

It's also good evidence that Martin Odersky, one of the most intelligent language designers alive today, is willing to do a lot to support named arguments in his language :-)

I have all respect for Odersky's competence, but that is beside the point. Design decisions are always taken in a context, and it's not impossible he would've had decided otherwise in a different context. D is a rich, powerful language _now_. It has classic features present in many languages, and a few features that are not present in many. Their full combination is not present in any other language, and creates a unique context. We've been historically trigger happy about discussing adding features in this group. This is not unique to D - all languages underwent the same process. But at this point it is a necessity that we start migrating our mindset from an endless wishlist - towards finding ingenious solutions within the language. Again, this is the case for every single language there is. Combining existing features towards new ends is in some ways more difficult than language design because you play within a confined ground, and I am a bit disappointed that a few posters have shown only contempt for such an effort.

The Herb Sutter interview that you recently posted a link to has an interesting point of view on that. One of the reasons that lambdas were added to C++0x was because Boost had shown how close you could get there using the language as it was and that it just wasn't good enough. Lambdas were added to the language precisely because they couldn't be done reasonably without additional language supported. On the other hand, other stuff that they added which Boost had tried to do - such as shared_ptr - were added as library solutions, because they worked as library solutions. As you've said, we've reached the point that D is powerful enough and complicated enough that we should be first trying to see how well we can solve problems using the language itself rather than adding new features to it. As we do that, we should be able to see what is reasonably feasible within the language as it is and what just doesn't work. As we find things that just don't work but which we really want to be able to do, we can look at adding features to the language to deal with them, but we should definitely be looking at using the language as it is first. In this particular case, while named arguments might arguably be nice, they're "nice to have," not a necessity. The question is how close we can get to having reasonable yes/no enums like we've been trying to do but without excessive boilerplate code. We may decide to add named arguments later, but D is really at the point that its current features need to be completely ironed out before we look at adding additional features that we don't really need. I think that there _are_ features that we need to look at adding in some form or other (such as conditional attributes) in order to solve current problems in the language (such as the inability to use many attributes - such as pure and safe - with templates without excessive duplication of code). But if a feature does not solve a pressing problem and/or can be reasonably solved by improving Phobos, then we should be improving Phobos. - Jonathan M Davis
Jun 10 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Wait, Walter wants to fix this? IIRC just a few days ago he made a
post on how this would be a bad feature because it hides imports in
arbitrary places. I guess he changed his mind..
Jun 10 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 6/11/11, Walter Bright <newshound2 digitalmars.com> wrote:
 On 6/10/2011 6:15 PM, Andrej Mitrovic wrote:
 Wait, Walter wants to fix this? IIRC just a few days ago he made a
 post on how this would be a bad feature because it hides imports in
 arbitrary places.

I did?

Hmm. It might have been a bug in the matrix, and I misplaced you for someone else. :]
Jun 10 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 6/11/11, bearophile <bearophileHUGS lycos.com> wrote:
 But I don't want this
 feature, overall I think it will not improve the code.

I've found someone that contradicts you: http://www.digitalmars.com/d/archives/digitalmars/D/Function-local_imports_109317.html
Jun 10 2011
prev sibling parent so <so so.so> writes:
 My take on this is that we shouldn't try to reinvent the boolean in the
 standard library.

I think this characterization is wrong. Let me replace the meaningless Abc with an actual example, e.g. OpenRight in std.algorithm. OpenRight is not a Boolean. Its *representation* is Boolean. It is categorical data with two categories. You can represent it with an unstructured Boolean the same way you can represent an automaton state with an unstructured integer or temperature with an unstructured double, but then you'd have the disadvantages that dimensional analysis libraries are solving.

Quite contrary i think it is pretty much spot on, if it is not but just its representation is boolean so is every other usage of boolean. The only reason we use an enum instead of simple bool is self documentation "fun(OpenRight.yes)". You simply can't deny the named arguments solve not only this particular issue but the entire area nicely "fun(openRight:true, width:4, height:3, depth:5)".
Jun 12 2011