www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Eliminate assert and lazy from D?

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Right now, the language has enough power to express assert as a library 
function, as opposed to a primitive construct. (See e.g. enforce.) I 
think it would be good to relegate assert to object.d.

This also brings up "lazy", which seems to be quite botched. Are there 
suggestions on how to replicate its functionality in a different way? I 
even seem to recall lazy was discussed as a disadvantage in the recent 
dialog on reddit, see

http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/

I personally believe it's useful to be able to pass an unevaluated 
expression into a function, for example assert and enforce themselves 
use that.

But let's open this for discussion: should assert and/or lazy be 
removed? If not, why not? It yes, why? How can we replicate their 
functionality?


Andrei
Oct 12 2009
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 13 Oct 2009 00:33:57 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Right now, the language has enough power to express assert as a library  
 function, as opposed to a primitive construct. (See e.g. enforce.) I  
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there  
 suggestions on how to replicate its functionality in a different way? I  
 even seem to recall lazy was discussed as a disadvantage in the recent  
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/

 I personally believe it's useful to be able to pass an unevaluated  
 expression into a function, for example assert and enforce themselves  
 use that.

 But let's open this for discussion: should assert and/or lazy be  
 removed? If not, why not? It yes, why? How can we replicate their  
 functionality?


 Andrei

Well, a lazy 'variable' is really a delegate of an expression, so implicit conversion of an expression to a delegate would be one way to remove lazy. (Not sure how practical/easy that is though) And then assert (I think) becomes void assert( bool delegate() expr, string delegate() msg ) { debug { if(!expr) throw new Exception(msg); } }
Oct 12 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Robert Jacques wrote:
 On Tue, 13 Oct 2009 00:33:57 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Right now, the language has enough power to express assert as a 
 library function, as opposed to a primitive construct. (See e.g. 
 enforce.) I think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there 
 suggestions on how to replicate its functionality in a different way? 
 I even seem to recall lazy was discussed as a disadvantage in the 
 recent dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its
completely_blowing/ 


 I personally believe it's useful to be able to pass an unevaluated 
 expression into a function, for example assert and enforce themselves 
 use that.

 But let's open this for discussion: should assert and/or lazy be 
 removed? If not, why not? It yes, why? How can we replicate their 
 functionality?


 Andrei

Well, a lazy 'variable' is really a delegate of an expression, so implicit conversion of an expression to a delegate would be one way to remove lazy. (Not sure how practical/easy that is though)

Yah, that's how the feature was initially proposed.
 And then assert (I think) becomes
 
 void assert( bool delegate() expr, string delegate() msg ) {
     debug {
         if(!expr)
             throw new Exception(msg);
     }
 }
 

It's simpler actually: debug void assert(T)( T expr, string delegate() msg ) { if(!expr) throw new Exception(msg); } else void assert(T)( T delegate(), string delegate() ) { } Hm, actually it's more complicated than your version :o). Andrei
Oct 12 2009
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Mon, Oct 12, 2009 at 11:33:57PM -0500, Andrei Alexandrescu wrote:
 Right now, the language has enough power to express assert as a library 
 function, as opposed to a primitive construct. (See e.g. enforce.) I 
 think it would be good to relegate assert to object.d.

What about static assert? Can it be moved to the library too? If not, it seems kinda weird that assert() is just a lib function, but if you put static before it, it becomes a completely different thing.
 I personally believe it's useful to be able to pass an unevaluated 
 expression into a function, for example assert and enforce themselves 
 use that.

I pretty rarely use it, but I'd be sad to see it go - it really does make a few things more elegant. -- Adam D. Ruppe http://arsdnet.net
Oct 12 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Adam D. Ruppe wrote:
 On Mon, Oct 12, 2009 at 11:33:57PM -0500, Andrei Alexandrescu wrote:
 Right now, the language has enough power to express assert as a library 
 function, as opposed to a primitive construct. (See e.g. enforce.) I 
 think it would be good to relegate assert to object.d.

What about static assert? Can it be moved to the library too? If not, it seems kinda weird that assert() is just a lib function, but if you put static before it, it becomes a completely different thing.

That kinda takes the wind out of the sails of the "remove assert" ship.
 I personally believe it's useful to be able to pass an unevaluated 
 expression into a function, for example assert and enforce themselves 
 use that.

I pretty rarely use it, but I'd be sad to see it go - it really does make a few things more elegant.

Yah, me too, enforce in particular is a happy beneficiary. Andrei
Oct 12 2009
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Andrei Alexandrescu wrote:
 Adam D. Ruppe wrote:
 If not, it seems kinda weird that assert() is just a lib function, but if
 you put static before it, it becomes a completely different thing.

That kinda takes the wind out of the sails of the "remove assert" ship.

It randomly occurred to me earlier today that one *could* implement static assert in the library, albeit with a different (sensical) name, IF the compiler guaranteed a pragma(halt) or pragma(exit) that prematurely terminates a compile the same way current static assert does. Given that, a template in the library could output a custom message with pragma(msg) and then issue the halt. Its really just taking static assert's check expression away from it and giving it a new name... but still. The downside is having a pragma that every compiler would actually *have* to implement (to be worth using at least). -- Chris Nicholson-Sauls
Oct 15 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 13 Oct 2009 01:17:19 -0400, Adam D. Ruppe  
<destructionator gmail.com> wrote:
[snip]
 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.

I pretty rarely use it, but I'd be sad to see it go - it really does make a few things more elegant.

I use lazy for C function wrapping (i.e. converting C error codes to exceptions and/or taking a corrective action based on the error code and re-running the C function).
Oct 12 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 This also brings up "lazy", which seems to be quite botched. Are there 
 suggestions on how to replicate its functionality in a different way? I 
 even seem to recall lazy was discussed as a disadvantage in the recent 
 dialog on reddit, see
 
 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/

I refuse that critics about lazy. They know D far less than me. I like lazy as it is now, I use it often. It allows me to simulate (in a not perfect way, but sometimes acceptable) Python list comphrensions that no D dev seems interested in adding (or even understanding why they are useful, it seems) to the D language. General note: removing features from a language, making a language more general to allow programmers to implement such feature by themselves, sometimes looks positive. But you must keep in mind that it also has some drawbacks and costs. So you must always balance such costs with such advantages. For example compilation times and compilation memory may grow, the syntax may become a little worse, recovery in case of programmer/syntax mistakes may be a little worse, and error messages may become a little (or a lot) worse. The complexity of the language may increase, so people need a bit more time to learn the language (while learning higher-level built-in features often doesn't require a lot of time). A higher number of low level & general features (necessary to manually implement the higher level features that have being removed) make the language more flexible, but this is the kind of flexibility of an "amoeba", like Forth & Lisp, that despite being very flexible languages with 30-45+ years of life, can become hard to use, quite hard to understand, and so on. Languages that hope to become very widespread have to offer a very well chosen set of features, must not offer too much flexibility, they need a certain amount of rigidity and "internal constraints" that make them a bit less flexible and nice, but make them fit for teams of programmers to build large programs (see the success of Java/C#, etc). So every time you want to remove a higher-level built-in feature you have to think about those factors too. Bye, bearophile
Oct 12 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
bearophile wrote:
 Andrei Alexandrescu:
 
 This also brings up "lazy", which seems to be quite botched. Are
 there suggestions on how to replicate its functionality in a
 different way? I even seem to recall lazy was discussed as a
 disadvantage in the recent dialog on reddit, see
 
 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/
 

I refuse that critics about lazy. They know D far less than me. I like lazy as it is now, I use it often. It allows me to simulate (in a not perfect way, but sometimes acceptable) Python list comphrensions that no D dev seems interested in adding (or even understanding why they are useful, it seems) to the D language.

I use lazy too, it is sometimes useful. The problem is that lazy is very much an oddball. It's a storage class that actually changes the type of a value. You sometimes need to add parens to get the value of a lazy variable, and sometimes not. It's unclear how lazy works with forwarding and how it interacts with templates. One litmus test is that it's very difficult to explain someone how lazy exactly works. I think it's a bad feature, and within reason we should clean the language of bad features.
 General note: removing features from a language, making a language
 more general to allow programmers to implement such feature by
 themselves, sometimes looks positive. But you must keep in mind that
 it also has some drawbacks and costs. So you must always balance such
 costs with such advantages. For example compilation times and
 compilation memory may grow, the syntax may become a little worse,
 recovery in case of programmer/syntax mistakes may be a little worse,
 and error messages may become a little (or a lot) worse. The
 complexity of the language may increase, so people need a bit more
 time to learn the language (while learning higher-level built-in
 features often doesn't require a lot of time). A higher number of low
 level & general features (necessary to manually implement the higher
 level features that have being removed) make the language more
 flexible, but this is the kind of flexibility of an "amoeba", like
 Forth & Lisp, that despite being very flexible languages with 30-45+
 years of life, can become hard to use, quite hard to understand, and
 so on. Languages that hope to become very widespread have to offer a
 very well chosen set of features, must not offer too much
 flexibility, they need a certain amount of rigidity and "internal
 constraints" that make them a bit less flexible and nice, but make
 them fit for teams of programmers to build large programs (see the
 success of Java/C#, etc). So every time you want to remove a
 higher-level built-in feature you have to think about those factors
 too.

IMHO what makes a language real hard to learn and use is the presence of misdesigned features. Then I'm not sure what you enjoy. Usually you're all for adding features (hey, you just brought up the switch again! isn't that ironic?) and cleaning up bad parts of the language, and now all of a sudden you wax poetic about this and that and the other, few of which have anything to do with the topic at hand. Next time I'll try a post "Let's keep lazy in the language" - that's bound to get a better response. Andrei
Oct 12 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 IMHO what makes a language real hard to learn and use is the presence of 
 misdesigned features.

I don't agree, the situation is far more complex; good languages are the result of a fine balance between many opposed needs and constraints.
 and cleaning up bad parts of the language, and now 
 all of a sudden you wax poetic about this and that and the other, few of 
 which have anything to do with the topic at hand.

I was talking about language design in general, it was very in-topic in this thread. I try to help, but often I fail... I am sorry.
 Next time I'll try a post "Let's keep lazy in the language" - that's 
 bound to get a better response.

Good. Inverting points of view is often positive in discussions. It's one of the bases of dialectics. Bear hugs, bearophile
Oct 12 2009
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu Wrote:

 Usually you're 
 all for adding features (hey, you just brought up the switch again! 
 isn't that ironic?) and cleaning up bad parts of the language,

Sorry, I'm not a computer scientist, and surely I am not a language designer (especially for a C++-class language), so you may see some contradictions in what I sometimes say :-) I have brought up the switch again because I was nervous, after spending some time to find a bug caused by the current design of the switch. There are classes of bugs that aren't easy to avoid, but I think with a less bug-prone switch I may avoid bugs like the one I have removed from my code. One of the most basic part of the Zen of D is to help programmers to avoid bugs, where possible. I hate the idea of having 3 different switches in the language (that's why I was not happy to see the static switch, because a better redesign of the *second* switch was in order). But the current situation of switch is not good for D yet. Bye, bearophile
Oct 12 2009
parent "Craig Black" <craigblack2 cox.net> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:hb17v3$1e4r$1 digitalmars.com...
 Andrei Alexandrescu Wrote:

 Usually you're
 all for adding features (hey, you just brought up the switch again!
 isn't that ironic?) and cleaning up bad parts of the language,

Sorry, I'm not a computer scientist, and surely I am not a language designer (especially for a C++-class language), so you may see some contradictions in what I sometimes say :-) I have brought up the switch again because I was nervous, after spending some time to find a bug caused by the current design of the switch. There are classes of bugs that aren't easy to avoid, but I think with a less bug-prone switch I may avoid bugs like the one I have removed from my code. One of the most basic part of the Zen of D is to help programmers to avoid bugs, where possible. I hate the idea of having 3 different switches in the language (that's why I was not happy to see the static switch, because a better redesign of the *second* switch was in order). But the current situation of switch is not good for D yet. Bye, bearophile

Since it seems there are fundamental changes already going into D 2.0, I agree with bearophile. I don't like the syntax of switch, which is based on the old C switch syntax. Yuck! But I digress, this is not on topic. -Craig
Oct 13 2009
prev sibling parent language_fan <foo bar.com.invalid> writes:
Tue, 13 Oct 2009 02:50:11 -0400, bearophile thusly wrote:

 Andrei Alexandrescu Wrote:
 
 Usually you're
 all for adding features (hey, you just brought up the switch again!
 isn't that ironic?) and cleaning up bad parts of the language,

Sorry, I'm not a computer scientist, and surely I am not a language designer (especially for a C++-class language), so you may see some contradictions in what I sometimes say :-) I have brought up the switch again because I was nervous, after spending some time to find a bug caused by the current design of the switch. There are classes of bugs that aren't easy to avoid, but I think with a less bug-prone switch I may avoid bugs like the one I have removed from my code. One of the most basic part of the Zen of D is to help programmers to avoid bugs, where possible.

I thought the priorities were 1) efficient systems programming features 2) metaprogramming fun 3) easy to use (if you come from c/c++) 4) cool new high level features (DbC etc.) 5) other features that make writing bug-free code easier
 I hate the idea of having 3 different switches in the language (that's
 why I was not happy to see the static switch, because a better redesign
 of the *second* switch was in order). But the current situation of
 switch is not good for D yet.

A pattern matching switch which always returns a value, detects unhandled cases, matches more than just ints, enums, and strings, does not support break and goto, and automatically casts, would be nice.
Oct 15 2009
prev sibling next sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Andrei Alexandrescu schrieb:
 Right now, the language has enough power to express assert as a library
 function, as opposed to a primitive construct. (See e.g. enforce.) I
 think it would be good to relegate assert to object.d.
 
 This also brings up "lazy", which seems to be quite botched. Are there
 suggestions on how to replicate its functionality in a different way? I
 even seem to recall lazy was discussed as a disadvantage in the recent
 dialog on reddit, see
 
 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/
 
 
 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.
 
 But let's open this for discussion: should assert and/or lazy be
 removed? If not, why not? It yes, why? How can we replicate their
 functionality?
 
 
 Andrei

I have seen lazy only used in its own show case. In log functions. In Tango too it is used in log functions. I use delegates as function parameters often, but not lazy. This is because I may add parameters and on the caller site, IMO it must be obvious, this expression is not evaluated as others. Maybe it is acceptable to remove lazy and write logging statements with delegate and the curly braces. log({ "bla bla "~info }); A related issue with passing arguments, that i think needs a better solution in D are the variadic arg list. No magic param names and the possibility to pass this list - or a slice of it - to another function.
Oct 12 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Frank Benoit wrote:
 Andrei Alexandrescu schrieb:
 Right now, the language has enough power to express assert as a library
 function, as opposed to a primitive construct. (See e.g. enforce.) I
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there
 suggestions on how to replicate its functionality in a different way? I
 even seem to recall lazy was discussed as a disadvantage in the recent
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/


 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.

 But let's open this for discussion: should assert and/or lazy be
 removed? If not, why not? It yes, why? How can we replicate their
 functionality?


 Andrei

I have seen lazy only used in its own show case. In log functions. In Tango too it is used in log functions. I use delegates as function parameters often, but not lazy. This is because I may add parameters and on the caller site, IMO it must be obvious, this expression is not evaluated as others. Maybe it is acceptable to remove lazy and write logging statements with delegate and the curly braces. log({ "bla bla "~info });

std.contracts.enforce also uses it.
 A related issue with passing arguments, that i think needs a better
 solution in D are the variadic arg list. No magic param names and the
 possibility to pass this list - or a slice of it - to another function.

I'm hoping that template variadics + arrays of Variant cover all needs. Andrei
Oct 12 2009
next sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Andrei Alexandrescu schrieb:
 Frank Benoit wrote:
 Andrei Alexandrescu schrieb:
 Right now, the language has enough power to express assert as a library
 function, as opposed to a primitive construct. (See e.g. enforce.) I
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there
 suggestions on how to replicate its functionality in a different way? I
 even seem to recall lazy was discussed as a disadvantage in the recent
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/



 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.

 But let's open this for discussion: should assert and/or lazy be
 removed? If not, why not? It yes, why? How can we replicate their
 functionality?


 Andrei

I have seen lazy only used in its own show case. In log functions. In Tango too it is used in log functions. I use delegates as function parameters often, but not lazy. This is because I may add parameters and on the caller site, IMO it must be obvious, this expression is not evaluated as others. Maybe it is acceptable to remove lazy and write logging statements with delegate and the curly braces. log({ "bla bla "~info });

std.contracts.enforce also uses it.

Yes, this is, both are functions that try to help the programmer itself and are part of the infrastructure. But is lazy useful for e.g. user libs? Is it useful in an API the user is not fully aware of? I mean if you call a function and you did not know the argument is lazy, it may have strange effects. This is why i would avoid lazy. I think the callers code should have the noticeable different syntax, and we already have that with the curly braces.
 A related issue with passing arguments, that i think needs a better
 solution in D are the variadic arg list. No magic param names and the
 possibility to pass this list - or a slice of it - to another function.

I'm hoping that template variadics + arrays of Variant cover all needs.

Doesn't that mean, each call with different arguments will instantiate another template instance?
Oct 12 2009
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-13 02:44:52 -0400, Frank Benoit <keinfarbton googlemail.com> said:

 I mean if you call a function and you did not know the argument is lazy,
 it may have strange effects. This is why i would avoid lazy. I think the
 callers code should have the noticeable different syntax, and we already
 have that with the curly braces.

Hum, side effects... I'm thinking lazy makes more sense if it was forcing the expression to be pure. With provably no side effects, this would make lazy a good optimization technique you can opt-in whenever you need to. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 13 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Frank Benoit wrote:
 Andrei Alexandrescu schrieb:
 Frank Benoit wrote:
 Andrei Alexandrescu schrieb:
 Right now, the language has enough power to express assert as a library
 function, as opposed to a primitive construct. (See e.g. enforce.) I
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there
 suggestions on how to replicate its functionality in a different way? I
 even seem to recall lazy was discussed as a disadvantage in the recent
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/



 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.

 But let's open this for discussion: should assert and/or lazy be
 removed? If not, why not? It yes, why? How can we replicate their
 functionality?


 Andrei

Tango too it is used in log functions. I use delegates as function parameters often, but not lazy. This is because I may add parameters and on the caller site, IMO it must be obvious, this expression is not evaluated as others. Maybe it is acceptable to remove lazy and write logging statements with delegate and the curly braces. log({ "bla bla "~info });


Yes, this is, both are functions that try to help the programmer itself and are part of the infrastructure. But is lazy useful for e.g. user libs? Is it useful in an API the user is not fully aware of? I mean if you call a function and you did not know the argument is lazy, it may have strange effects. This is why i would avoid lazy. I think the callers code should have the noticeable different syntax, and we already have that with the curly braces.

I'm wary about magic capabilities that are reserved only to the core compiler and library. Among other things, one wouldn't be able to write their own logging/enforcement library. Historically, Walter has been prone to magic, but since recently he has started systematically using lowering - implement a higher-level feature by rewriting it in terms of simpler D code. He eliminated wads of code from the compiler that way. Maybe it's just me, but I clearly remember: after my first Pascal class, when I learned that writeln is a "special" function that takes variadic arguments, my only desire has been to be able to write "writeln" itself.
 A related issue with passing arguments, that i think needs a better
 solution in D are the variadic arg list. No magic param names and the
 possibility to pass this list - or a slice of it - to another function.


Doesn't that mean, each call with different arguments will instantiate another template instance?

The template is small - all it does is pack the arguments. void funImpl(Variant[] args) { ... } void fun(T...)(T args) { return funImpl(variantArray(args)); } Andrei
Oct 13 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Maybe it's just me, but I clearly remember: after my first Pascal class, 
 when I learned that writeln is a "special" function that takes variadic 
 arguments, my only desire has been to be able to write "writeln" itself.

Have you seen the asm produced by a small console D2 program? Even if you do very little there's a good amount of templates. That's one of the prices you have to pay, I was talking about in the poetic part of my post. Bye, bearophile
Oct 13 2009
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 10/13/09 08:21, Andrei Alexandrescu wrote:
 Frank Benoit wrote:
 Andrei Alexandrescu schrieb:
 Right now, the language has enough power to express assert as a library
 function, as opposed to a primitive construct. (See e.g. enforce.) I
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there
 suggestions on how to replicate its functionality in a different way? I
 even seem to recall lazy was discussed as a disadvantage in the recent
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/



 I personally believe it's useful to be able to pass an unevaluated
 expression into a function, for example assert and enforce themselves
 use that.

 But let's open this for discussion: should assert and/or lazy be
 removed? If not, why not? It yes, why? How can we replicate their
 functionality?


 Andrei

I have seen lazy only used in its own show case. In log functions. In Tango too it is used in log functions. I use delegates as function parameters often, but not lazy. This is because I may add parameters and on the caller site, IMO it must be obvious, this expression is not evaluated as others. Maybe it is acceptable to remove lazy and write logging statements with delegate and the curly braces. log({ "bla bla "~info });

std.contracts.enforce also uses it.
 A related issue with passing arguments, that i think needs a better
 solution in D are the variadic arg list. No magic param names and the
 possibility to pass this list - or a slice of it - to another function.

I'm hoping that template variadics + arrays of Variant cover all needs. Andrei

Templates don't work as virtual methods. Arrays of variants will probably not interact well with C variadic functions.
Oct 13 2009
prev sibling next sibling parent reply Jeremie Pelletier <jeremiep gmail.com> writes:
Andrei Alexandrescu wrote:
 Right now, the language has enough power to express assert as a library 
 function, as opposed to a primitive construct. (See e.g. enforce.) I 
 think it would be good to relegate assert to object.d.
 
 This also brings up "lazy", which seems to be quite botched. Are there 
 suggestions on how to replicate its functionality in a different way? I 
 even seem to recall lazy was discussed as a disadvantage in the recent 
 dialog on reddit, see
 
 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its
completely_blowing/ 
 
 
 I personally believe it's useful to be able to pass an unevaluated 
 expression into a function, for example assert and enforce themselves 
 use that.
 
 But let's open this for discussion: should assert and/or lazy be 
 removed? If not, why not? It yes, why? How can we replicate their 
 functionality?
 
 
 Andrei

lazy is a great feature of D, although you need some sort of usage convention to not get confused with it. For example, there is no way to tell a parameter is lazy from a function call, you need to look at the prototype. But the same can be said with ref and out too so if you remove lazy you also need to rethink these two. I therefore made myself a simple convention on how I use lazy: if the value is evaluated only once I use lazy, otherwise I use a delegate. This makes it clear from the call context what I'm doing. Sometimes I use lazy for values evaluated multiple times (I did it in the json module i posted to D.announce) when the method is private because I'm too lazy (pun intended) to write a full delegate. Jeremie
Oct 12 2009
next sibling parent Frank Benoit <keinfarbton googlemail.com> writes:
Jeremie Pelletier schrieb:
 
 For example, there is no way to tell a parameter is lazy from a function
 call, you need to look at the prototype. But the same can be said with
 ref and out too so if you remove lazy you also need to rethink these two.
 

ref and out are not the same category of weirdness for the caller. the compiler will tell that a lvalue is needed for ref and out. But the expression may have side effects, evaluating never/once/multiple is easy to hide errors.
 I therefore made myself a simple convention on how I use lazy: if the
 value is evaluated only once I use lazy, otherwise I use a delegate.
 This makes it clear from the call context what I'm doing.

If it is evaluated exactly once, you do not need lazy at all. And if it may also not be evaluated, the callers code is not less safe as when evaluated multiple times.
Oct 12 2009
prev sibling parent language_fan <foo bar.com.invalid> writes:
Tue, 13 Oct 2009 08:51:16 +0200, Frank Benoit thusly wrote:

 If it is evaluated exactly once, you do not need lazy at all. And if it
 may also not be evaluated, the callers code is not less safe as when
 evaluated multiple times.

Call by name has its uses. E.g. custom control structures, infinite lists etc.
Oct 15 2009
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-13 00:33:57 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Right now, the language has enough power to express assert as a library 
 function, as opposed to a primitive construct. (See e.g. enforce.) I 
 think it would be good to relegate assert to object.d.

According to the spec, 'assert' also allows the compiler to know something will always be true, which could result in optimizations. The compiler also enforce that you have an assert(false) at the end of a function when the control flow can't be proven to never reach it. So no, 'assert' should stay in the language.
 This also brings up "lazy", which seems to be quite botched. Are there 
 suggestions on how to replicate its functionality in a different way?

There are two uses for 'lazy': 1. provide a statement that can be executed by the function you're calling to perform some action. 2. to give a lazy-evaluated value to the calling function, removing the cost of evaluation when unnecessary I'm willing use the delegate literal syntax for case 1. But I'd like to keep 'lazy' for case 2. The problem with case 2 is that it's more an optimization technique used within the function (lazy evaluation) and it would be better if the caller didn't have to care about such details. So here's my idea to fix 'lazy': make sure 'lazy' can only work with case 2 by forcing the lazy expression to be pure, thus with no side effects. This way, 'lazy' becomes an almost-transparent optimization technique and stays true to its meaning of 'lazy evaluation'. And it'll give more optimization opportunities to the compiler. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 13 2009
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Right now, the language has enough power to express assert as a library 
 function, as opposed to a primitive construct. (See e.g. enforce.) I 
 think it would be good to relegate assert to object.d.
 
 This also brings up "lazy", which seems to be quite botched. Are there 
 suggestions on how to replicate its functionality in a different way? I 
 even seem to recall lazy was discussed as a disadvantage in the recent 
 dialog on reddit, see
 
 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its
completely_blowing/ 
 
 
 I personally believe it's useful to be able to pass an unevaluated 
 expression into a function, for example assert and enforce themselves 
 use that.
 
 But let's open this for discussion: should assert and/or lazy be 
 removed? If not, why not? It yes, why? How can we replicate their 
 functionality?
 
 
 Andrei

assert: should remain. It is important to the compiler. I can easily imagine it participating in range checking. uint x = whatever(); assert(x<100); ubyte b = x; // This implicit conversion is OK; we know x is in the appropriate range. lazy: should be removed. It seems to me that 'lazy' covers just a single use case for macros.
Oct 13 2009
parent Kagamin <spam here.lot> writes:
Don Wrote:

 assert: should remain. It is important to the compiler. I can easily 
 imagine it participating in range checking.
 uint x = whatever();
 assert(x<100);
 ubyte b = x;  // This implicit conversion is OK; we know x is in the 
 appropriate range.

how about this? long more=fileLength; ubyte[256] buff; for(; more>=buff.length ; more-=buff.length) { //read from file, no breaks } //last read read(file,buff.ptr,more); auto rd=buff[0..more]; //can't cast long to uint
Oct 13 2009
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)
Oct 13 2009
next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 13 Oct 2009 17:06:25 +0400, downs <default_357-line yahoo.de>  
wrote:

 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Wow, indeed!
Oct 13 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
downs wrote:
 Did you know the following code compiles?
 
 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Gosh!!! What's happening over here? I even tried this: import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy! Andrei
Oct 13 2009
next sibling parent Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 downs wrote:
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Gosh!!! What's happening over here? I even tried this: import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy! Andrei

There's a bug report about it, from Sean: bugzilla 1069.
Oct 13 2009
prev sibling parent reply Jeremie Pelletier <jeremiep gmail.com> writes:
Leandro Lucarella wrote:
 Andrei Alexandrescu, el 13 de octubre a las 10:30 me escribiste:
 downs wrote:
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
  debug if (!cond) {
    string str;
    foreach (dg; dgs) str ~= dg();
    throw new Exception(str);
  }
 }

 void main() {
  Assert(false, "O hai thar! ");
 }

It's true! :)

import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy!

What is the relation between assert and pure/nothrow? Is assert allowed? I think it should be, since an assert is expressing a very essential property of the software, it can't happen in a normal flow of the program. If this is the case, I guess assert should be kept as a language construct so it can be always be used in pure/nothrow functions.

It works for the reason you said, assertions either guard against an unreachable code path or invalid values. AssertError throwables aren't meant to be recovered from (as should any Error) so they're perfectly fine in pure or nothrow contexts. I often use assert(0) to mark unreachable paths, and the compiler don't warn me that some paths of a function have no return value. For that reason I also want assert() to stay a compiler intrinsic, especially since having assert() as a library routine and static assert() as a compiler feature sounds weird. Jeremie
Oct 13 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jeremie Pelletier wrote:
 Leandro Lucarella wrote:
 Andrei Alexandrescu, el 13 de octubre a las 10:30 me escribiste:
 downs wrote:
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
  debug if (!cond) {
    string str;
    foreach (dg; dgs) str ~= dg();
    throw new Exception(str);
  }
 }

 void main() {
  Assert(false, "O hai thar! ");
 }

It's true! :)

import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy!

What is the relation between assert and pure/nothrow? Is assert allowed? I think it should be, since an assert is expressing a very essential property of the software, it can't happen in a normal flow of the program. If this is the case, I guess assert should be kept as a language construct so it can be always be used in pure/nothrow functions.

It works for the reason you said, assertions either guard against an unreachable code path or invalid values. AssertError throwables aren't meant to be recovered from (as should any Error) so they're perfectly fine in pure or nothrow contexts. I often use assert(0) to mark unreachable paths, and the compiler don't warn me that some paths of a function have no return value. For that reason I also want assert() to stay a compiler intrinsic, especially since having assert() as a library routine and static assert() as a compiler feature sounds weird. Jeremie

I think that's sensible, and thanks all for revealing reasons for assert to stay in the language. As far as lazy goes, I think the lazy variadic functions are a compelling feature that renders lazy unnecessary. I plan to put no reference to lazy in TDPL. (Before someone else leaves the group: I just talked to Walter and he approved that.) Andrei
Oct 13 2009
parent Jeremie Pelletier <jeremiep gmail.com> writes:
Andrei Alexandrescu wrote:
 Jeremie Pelletier wrote:
 Leandro Lucarella wrote:
 Andrei Alexandrescu, el 13 de octubre a las 10:30 me escribiste:
 downs wrote:
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
  debug if (!cond) {
    string str;
    foreach (dg; dgs) str ~= dg();
    throw new Exception(str);
  }
 }

 void main() {
  Assert(false, "O hai thar! ");
 }

It's true! :)

import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy!

What is the relation between assert and pure/nothrow? Is assert allowed? I think it should be, since an assert is expressing a very essential property of the software, it can't happen in a normal flow of the program. If this is the case, I guess assert should be kept as a language construct so it can be always be used in pure/nothrow functions.

It works for the reason you said, assertions either guard against an unreachable code path or invalid values. AssertError throwables aren't meant to be recovered from (as should any Error) so they're perfectly fine in pure or nothrow contexts. I often use assert(0) to mark unreachable paths, and the compiler don't warn me that some paths of a function have no return value. For that reason I also want assert() to stay a compiler intrinsic, especially since having assert() as a library routine and static assert() as a compiler feature sounds weird. Jeremie

I think that's sensible, and thanks all for revealing reasons for assert to stay in the language. As far as lazy goes, I think the lazy variadic functions are a compelling feature that renders lazy unnecessary. I plan to put no reference to lazy in TDPL. (Before someone else leaves the group: I just talked to Walter and he approved that.) Andrei

I wouldn't mind lazy going away, its something that can be 100% covered by delegates and closures, maybe keep lazy as a lazy way of writing a delegate? 'lazy int foo' could semantically equivalent to 'scope int delegate() foo'. It would get called as {return 1;} and evaluated as foo(). Jeremie
Oct 13 2009
prev sibling next sibling parent reply Max Samukha <spambox d-coding.com> writes:
On Tue, 13 Oct 2009 15:06:25 +0200, downs <default_357-line yahoo.de>
wrote:

Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Yes, it is documented. "Lazy Variadic Functions" on "Functions" page.
Oct 13 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Max Samukha wrote:
 On Tue, 13 Oct 2009 15:06:25 +0200, downs <default_357-line yahoo.de>
 wrote:
 
 Did you know the following code compiles?

 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Yes, it is documented. "Lazy Variadic Functions" on "Functions" page.

Awesome. I'll replace the use of lazy in enforce() with that. Andrei
Oct 13 2009
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
downs wrote:
 Did you know the following code compiles?
 
 module test;

 import std.stdio;

 void Assert(bool cond, string delegate()[] dgs...) {
   debug if (!cond) {
     string str;
     foreach (dg; dgs) str ~= dg();
     throw new Exception(str);
   }
 }

 void main() {
   Assert(false, "O hai thar! ");
 }

It's true! :)

Here is a funny consequence of this amusing fact: if you overload opAssign in a struct with lazy T[] dgs..., you can achieve the following syntax
     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With = Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };

Oct 13 2009
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
downs wrote:
 
 Here is a funny consequence of this amusing fact:
 
 if you overload opAssign in a struct with lazy T[] dgs..., you can achieve the
following syntax
 
 
     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With = Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };


That's... just beautiful... -- Chris Nicholson-Sauls
Oct 13 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Chris Nicholson-Sauls wrote:
 downs wrote:
 Here is a funny consequence of this amusing fact:

 if you overload opAssign in a struct with lazy T[] dgs..., you can 
 achieve the following syntax


     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With = 
 Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };


That's... just beautiful... -- Chris Nicholson-Sauls

Not getting it... could someone please explain? Andrei
Oct 13 2009
parent reply Jeremie Pelletier <jeremiep gmail.com> writes:
Andrei Alexandrescu wrote:
 Chris Nicholson-Sauls wrote:
 downs wrote:
 Here is a funny consequence of this amusing fact:

 if you overload opAssign in a struct with lazy T[] dgs..., you can 
 achieve the following syntax


     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With = 
 Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };


That's... just beautiful... -- Chris Nicholson-Sauls

Not getting it... could someone please explain? Andrei

From what I get, he has something like this: struct WithFlag(int OP, bool enable) { static void opAssign(T)(lazy T next) { static if(enable) glEnable(OP); else glDisable(OP); next(); } } struct WithDepthMask(bool enable) { static void opAssign(T)(lazy T next) { glDepthMask(enable); next(); } } struct Tex { void opAssign(T)(lazy T next) { glBindTexture(_tex); next(); } } struct Quads { static void opAssign(T)(lazy T commands) { glBegin(GL_QUADS); commands(); glEnd(); } } I don't know if thats his exact code, but from what I can remember of gl from memory it should look like this. Jeremie
Oct 13 2009
parent downs <default_357-line yahoo.de> writes:
Jeremie Pelletier wrote:
 Andrei Alexandrescu wrote:
 Chris Nicholson-Sauls wrote:
 downs wrote:
 Here is a funny consequence of this amusing fact:

 if you overload opAssign in a struct with lazy T[] dgs..., you can
 achieve the following syntax


     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With =
 Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };


That's... just beautiful... -- Chris Nicholson-Sauls

Not getting it... could someone please explain? Andrei

From what I get, he has something like this: struct WithFlag(int OP, bool enable) { static void opAssign(T)(lazy T next) { static if(enable) glEnable(OP); else glDisable(OP); next(); } } struct WithDepthMask(bool enable) { static void opAssign(T)(lazy T next) { glDepthMask(enable); next(); } } struct Tex { void opAssign(T)(lazy T next) { glBindTexture(_tex); next(); } } struct Quads { static void opAssign(T)(lazy T commands) { glBegin(GL_QUADS); commands(); glEnd(); } } I don't know if thats his exact code, but from what I can remember of gl from memory it should look like this. Jeremie

Very close. There's another workaround required to enable the = {} syntax. The T in question can either be a void, in which case we're assigning a function call, or a void delegate(), in which case we're assigning a subscope. Because the parameter is lazy, in the case of void delegate() we actually have to call it doubly nestedly! This leads to the following code.
 const string LazyCall="
 static if (is(T==void)) t();
 else static if (is(T==void delegate())) t()();
 else static assert(false, T.stringof);
 ";

...
 template PrimitiveScope(string NAME, string WHICH) {
   const string PrimitiveScope="struct "~NAME~" {
     static void opAssign(T)(lazy T t) {
       glBegin("~WHICH~"); scope(exit) glEnd();
       "~LazyCall~"
     }
   }";
 }

...
 mixin(Concat!(MAP!(PrimitiveScope, 2,
   "Points", "GL_POINTS", "Lines", "GL_LINES",
   "LineLoop", "GL_LINE_LOOP", "LineStrip", "GL_LINE_STRIP",
   "Triangles", "GL_TRIANGLES", "TriangleStrip", "GL_TRIANGLE_STRIP",
   "TriangleFan", "GL_TRIANGLE_FAN", "Quads", "GL_QUADS",
   "QuadStrip", "GL_QUAD_STRIP", "Polygon", "GL_POLYGON"
 )));

:deranged grin: I love templates!
Oct 14 2009
prev sibling parent Jeremie Pelletier <jeremiep gmail.com> writes:
Chris Nicholson-Sauls wrote:
 downs wrote:
 Here is a funny consequence of this amusing fact:

 if you overload opAssign in a struct with lazy T[] dgs..., you can 
 achieve the following syntax


     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With = 
 Quads = {
       foreach (i, q; qa) {
         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
         TexCoord(0f, 0f); Vertex(q.points[0]);
         TexCoord(1f, 0f); Vertex(q.points[1]);
         TexCoord(1f, 1f); Vertex(q.points[3]);
         TexCoord(0f, 1f); Vertex(q.points[2]);
       }
     };


That's... just beautiful... -- Chris Nicholson-Sauls

If you forget the fact that he is using GL's immediate mode which is slooooow, yeah it's beautiful, would be better with an interlaced vertex buffer :) Jeremie
Oct 13 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 13 Oct 2009 16:39:13 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 As far as lazy goes, I think the lazy variadic functions are a  
 compelling feature that renders lazy unnecessary.

Do you mean lazy in the way that lazy variadic functions *imply* lazy via typing their arguments as delegates, or simply only allow lazy variadic functions? If the latter, why must a lazy function be variadic? -Steve
Oct 13 2009
prev sibling next sibling parent "Vladimir Panteleev" <thecybershadow gmail.com> writes:
On Tue, 13 Oct 2009 07:33:57 +0300, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Right now, the language has enough power to express assert as a library  
 function, as opposed to a primitive construct. (See e.g. enforce.) I  
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there  
 suggestions on how to replicate its functionality in a different way? I  
 even seem to recall lazy was discussed as a disadvantage in the recent  
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/

 I personally believe it's useful to be able to pass an unevaluated  
 expression into a function, for example assert and enforce themselves  
 use that.

 But let's open this for discussion: should assert and/or lazy be  
 removed? If not, why not? It yes, why? How can we replicate their  
 functionality?

No one seems to have mentioned this, but please don't overlook that when compiling in release mode, assert (or at least assert(0)) works as a compiler hint. -- Best regards, Vladimir mailto:thecybershadow gmail.com
Oct 13 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 13 Oct 2009 00:33:57 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Right now, the language has enough power to express assert as a library  
 function, as opposed to a primitive construct. (See e.g. enforce.) I  
 think it would be good to relegate assert to object.d.

 This also brings up "lazy", which seems to be quite botched. Are there  
 suggestions on how to replicate its functionality in a different way? I  
 even seem to recall lazy was discussed as a disadvantage in the recent  
 dialog on reddit, see

 http://www.reddit.com/r/programming/comments/9qf8i/i_wrote_some_d_today_and_its_completely_blowing/

 I personally believe it's useful to be able to pass an unevaluated  
 expression into a function, for example assert and enforce themselves  
 use that.

 But let's open this for discussion: should assert and/or lazy be  
 removed? If not, why not? It yes, why? How can we replicate their  
 functionality?

How to trigger assert when no -debug or -release flag is set? Is there a flag we can trigger on? From what I understand assert triggers when -debug or no flag is set, but not when -release flag is set. -Steve
Oct 13 2009
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el 13 de octubre a las 10:30 me escribiste:
 downs wrote:
Did you know the following code compiles?

module test;

import std.stdio;

void Assert(bool cond, string delegate()[] dgs...) {
  debug if (!cond) {
    string str;
    foreach (dg; dgs) str ~= dg();
    throw new Exception(str);
  }
}

void main() {
  Assert(false, "O hai thar! ");
}

It's true! :)

Gosh!!! What's happening over here? I even tried this: import std.stdio; void Assert(bool cond, string delegate()[] dgs...) { if (!cond) { string str; foreach (dg; dgs) str ~= dg(); throw new Exception(str); } } string fun(string a, string b) { writeln("Concatenating..."); return a ~ b; } void main() { Assert(true, fun("O hai thar! ", "wyda")); Assert(false, fun("O hai thar! ", "wyda")); } This example only prints "Concatenatning..." once, meaning that fun is also lazified!!! This is very exciting! The fact that this little anomaly hasn't caused trouble is a good sign it could actually replace lazy!

What is the relation between assert and pure/nothrow? Is assert allowed? I think it should be, since an assert is expressing a very essential property of the software, it can't happen in a normal flow of the program. If this is the case, I guess assert should be kept as a language construct so it can be always be used in pure/nothrow functions. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- En la calle me crucé con un señor muy correcto, que habitualmente anda en Falcon; iba corriendo con dos valijas en la mano y dijo: "Voy para Miami, tiene algún mensaje o ..." y le dije: "No, no, no..." -- Extra Tato (1983, Triunfo de Alfonsín)
Oct 13 2009