Thread overview
Red Code, Green Code (nwcpp video)
May 07, 2007
sergk
May 07, 2007
Stephen Waits
May 08, 2007
janderson
May 08, 2007
Pragma
May 09, 2007
janderson
May 09, 2007
Pragma
May 10, 2007
David B. Held
May 10, 2007
Pragma
May 09, 2007
Knud Soerensen
May 09, 2007
Stephen Waits
May 07, 2007
I've just noticed a Northwest C++ Users Group presentation
"Red Code, Green Code:  Generalizing const" by Scott Meyers, and found it quite interesting.

So here it is:
http://nwcpp.org/Meetings/2007/04.html


PS./OT: seems Scott do not really enjoying C++ template meta programming =)

-- serg.
May 07, 2007
sergk wrote:
> PS./OT: seems Scott do not really enjoying C++ template meta programming =)

Well, he *is* a pretty smart guy.

--Steve
May 08, 2007
sergk wrote:
> I've just noticed a Northwest C++ Users Group presentation
> "Red Code, Green Code:  Generalizing const" by Scott Meyers, and found it quite interesting.
> 
> So here it is:
> http://nwcpp.org/Meetings/2007/04.html
> 
> 
> PS./OT: seems Scott do not really enjoying C++ template meta programming =)
> 
> -- serg.

The next time some tries to argue library over language, or that templates in C++ are perfect, we should point them to that video.

PS - What would be the nicest way to do this in D using current syntax?
May 08, 2007
janderson wrote:
> sergk wrote:
>> I've just noticed a Northwest C++ Users Group presentation
>> "Red Code, Green Code:  Generalizing const" by Scott Meyers, and found it quite interesting.
>>
>> So here it is:
>> http://nwcpp.org/Meetings/2007/04.html
>>
>>
>> PS./OT: seems Scott do not really enjoying C++ template meta programming =)
>>
>> -- serg.
> 
> The next time some tries to argue library over language, or that templates in C++ are perfect, we should point them to that video.
> 
> PS - What would be the nicest way to do this in D using current syntax?

Well, we can trans-literate from the C++ code to get the same results.  Here I have an example that replaces the functionality from the vector template with tuples, and some additional template namespaces and operations to make it all come together.  The actual example is in the bottom third of this snippet.

(Mucking with code from http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!207.entry)

// This is placed in the Public Domain

template Tuple(V...){
	alias V Tuple;
}

template InTuple(Item){
	const bool InTuple = false;
}

template InTuple(Item,First,V...){
	static if(is(Item == First)){
		const bool InTuple = true;
	}
	else alias InTuple!(Item,V) InTuple;
}

template TupleRemoveAll(Item){
	alias Tuple!() TupleRemoveAll;
}

template TupleRemoveAll(Item,First,V...){
	static if(is(Item == First)){
		alias TupleRemoveAll!(Item,V) TupleRemoveAll;
	}
	else alias Tuple!(First,TupleRemoveAll!(Item,V)) TupleRemoveAll;
}

// use template 'struct' to prevent tuple flattening when passing constraints around
template Constraints(V...){
	alias V list;
}

template ConstraintRemove(alias Constraints){
	alias Constraints.list list;
}

template ConstraintRemove(alias Constraints,First,V...){
	alias Cosntraints!(TupleRemoveAll!(First,Constraints.list)) newConstraints;
	alias Tuple!(newConstraints,ConstraintRemove!(newConstraints,V)) list;
}

struct IgnoreConstraints {}

template ConstraintCheck(alias Local,Caller:IgnoreConstraints){
	const bool ConstraintCheck = true;
}

// ensure that all local constraints are satisfied by caller
template ConstraintCheck(alias Local,alias Caller){
	static if(Local.list.length > 0){
		static if(Caller.list.length > 0){
			alias Local.list[0] first;
			static if(InTuple!(Local.list[0],Caller.list)){
				alias Constraints!(TupleRemoveAll!(first,Local.list)) newLocalConstraints;
				alias ConstraintCheck!(newLocalConstraints,Caller) ConstraintCheck;
			}
			else{
				const bool ConstraintCheck = false;
			}
		}
		else{ // nothing left to check
			const bool ConstraintCheck = false;
		}		
	}
	else{ // nothing left to check
		const bool ConstraintCheck = true;
	}
}

// Here's the useful part:
struct ExceptionSafe {}
struct LGPLed {}
struct Reviewed {}

void f(alias CallerConstraints)(Params params){
    alias Constraints!(ExceptionSafe) MyConstraints;
    static assert(ConstraintCheck!(MyConstraints,CallerConstraints));
    /* do something */
}

void g(alias CallerConstraints)(){
    alias Constraints!(ExceptionSafe,Reviewed) MyConstraints;
    static assert(ConstraintCheck!(MyConstraints,CallerConstraints));

    // try to call the other function
    f!(MyConstraints)();  // error, trying to call unreviewed code from reviewed code
    f!(ConstraintRemove!(MyConstraints,Reviewed))(); // ok, ignore Reviewed constraint
    f!(IgnoreConstraints)(); // ok, explicitly ignore constraints entirely
}

void main(){
    alias Constraints!(ExceptionSafe,Reviewed) MyConstraints;
    g!(MyConstraints)();
}

This won't compile under DMD 0.012 and later - Bug 1196 keeps operations like InTuple!() from operating correctly.  So this is only half-tested.  There are also a few different ways one could implement this.  I opted for this particular definition of Constraints!() to allow for the ConstraintCheck!() operation to work for comparing two tuple lists (otherwise, they'd collapse into a single tuple).

Aside from the advantages that tuples offer, I'm having a hard time seeing a clear advantage over the C++ version.  We still get template bloat, and namespace concerns, plus it's not much more readable.  At a minimum, the lack of a need for a heavy amount of compile-time code is a clear advantage and I think (not sure here) the concerns about virtual methods are also addressed thanks to D's design.  So I think this edges out the C++ version rather invisibly.

-- 
- EricAnderton at yahoo
May 09, 2007
On Mon, 07 May 2007 10:58:24 -0400, sergk wrote:

> I've just noticed a Northwest C++ Users Group presentation
> "Red Code, Green Code:  Generalizing const" by Scott Meyers, and found it quite interesting.
> 
> So here it is:
> http://nwcpp.org/Meetings/2007/04.html
> 
Very good idea.

I am wondering if it is possible to extend the idea to ensure layering in code.

I normally use 5 layers.

Interface layer.
Application layer.
Domain layer.
Technical layer.
Platform layer.

The constrain on the code is that it should only make call in it own layer or the layer below.

I think it could be very useful.

Knud
May 09, 2007
Knud Soerensen wrote:
> 
> The constrain on the code is that it should only make call in it own layer
> or the layer below.
> 
> I think it could be very useful.

I think this is a really interesting idea.

--Steve
May 09, 2007
Pragma wrote:
> janderson wrote:
>> sergk wrote:
>>> I've just noticed a Northwest C++ Users Group presentation
>>> "Red Code, Green Code:  Generalizing const" by Scott Meyers, and found it quite interesting.
>>>
>>> So here it is:
>>> http://nwcpp.org/Meetings/2007/04.html
>>>
>>>
>>> PS./OT: seems Scott do not really enjoying C++ template meta programming =)
>>>
>>> -- serg.
>>
>> The next time some tries to argue library over language, or that templates in C++ are perfect, we should point them to that video.
>>
>> PS - What would be the nicest way to do this in D using current syntax?
> 
> Well, we can trans-literate from the C++ code to get the same results.  Here I have an example that replaces the functionality from the vector template with tuples, and some additional template namespaces and operations to make it all come together.  The actual example is in the bottom third of this snippet.
> 
> (Mucking with code from http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!207.entry)
> 
> // This is placed in the Public Domain
> 
> template Tuple(V...){
>     alias V Tuple;
> }
> 
> template InTuple(Item){
>     const bool InTuple = false;
> }
> 
> template InTuple(Item,First,V...){
>     static if(is(Item == First)){
>         const bool InTuple = true;
>     }
>     else alias InTuple!(Item,V) InTuple;
> }
> 
> template TupleRemoveAll(Item){
>     alias Tuple!() TupleRemoveAll;
> }
> 
> template TupleRemoveAll(Item,First,V...){
>     static if(is(Item == First)){
>         alias TupleRemoveAll!(Item,V) TupleRemoveAll;
>     }
>     else alias Tuple!(First,TupleRemoveAll!(Item,V)) TupleRemoveAll;
> }
> 
> // use template 'struct' to prevent tuple flattening when passing constraints around
> template Constraints(V...){
>     alias V list;
> }
> 
> template ConstraintRemove(alias Constraints){
>     alias Constraints.list list;
> }
> 
> template ConstraintRemove(alias Constraints,First,V...){
>     alias Cosntraints!(TupleRemoveAll!(First,Constraints.list)) newConstraints;
>     alias Tuple!(newConstraints,ConstraintRemove!(newConstraints,V)) list;
> }
> 
> struct IgnoreConstraints {}
> 
> template ConstraintCheck(alias Local,Caller:IgnoreConstraints){
>     const bool ConstraintCheck = true;
> }
> 
> // ensure that all local constraints are satisfied by caller
> template ConstraintCheck(alias Local,alias Caller){
>     static if(Local.list.length > 0){
>         static if(Caller.list.length > 0){
>             alias Local.list[0] first;
>             static if(InTuple!(Local.list[0],Caller.list)){
>                 alias Constraints!(TupleRemoveAll!(first,Local.list)) newLocalConstraints;
>                 alias ConstraintCheck!(newLocalConstraints,Caller) ConstraintCheck;
>             }
>             else{
>                 const bool ConstraintCheck = false;
>             }
>         }
>         else{ // nothing left to check
>             const bool ConstraintCheck = false;
>         }           }
>     else{ // nothing left to check
>         const bool ConstraintCheck = true;
>     }
> }
> 
> // Here's the useful part:
> struct ExceptionSafe {}
> struct LGPLed {}
> struct Reviewed {}
> 
> void f(alias CallerConstraints)(Params params){
>     alias Constraints!(ExceptionSafe) MyConstraints;
>     static assert(ConstraintCheck!(MyConstraints,CallerConstraints));
>     /* do something */
> }
> 
> void g(alias CallerConstraints)(){
>     alias Constraints!(ExceptionSafe,Reviewed) MyConstraints;
>     static assert(ConstraintCheck!(MyConstraints,CallerConstraints));
> 
>     // try to call the other function
>     f!(MyConstraints)();  // error, trying to call unreviewed code from reviewed code
>     f!(ConstraintRemove!(MyConstraints,Reviewed))(); // ok, ignore Reviewed constraint
>     f!(IgnoreConstraints)(); // ok, explicitly ignore constraints entirely
> }
> 
> void main(){
>     alias Constraints!(ExceptionSafe,Reviewed) MyConstraints;
>     g!(MyConstraints)();
> }
> 
> This won't compile under DMD 0.012 and later - Bug 1196 keeps operations like InTuple!() from operating correctly.  So this is only half-tested.  There are also a few different ways one could implement this.  I opted for this particular definition of Constraints!() to allow for the ConstraintCheck!() operation to work for comparing two tuple lists (otherwise, they'd collapse into a single tuple).
> 
> Aside from the advantages that tuples offer, I'm having a hard time seeing a clear advantage over the C++ version.  We still get template bloat, and namespace concerns, plus it's not much more readable.  At a minimum, the lack of a need for a heavy amount of compile-time code is a clear advantage and I think (not sure here) the concerns about virtual methods are also addressed thanks to D's design.  So I think this edges out the C++ version rather invisibly.
> 

Maybe something like C# user-definable attributes would help. (I'm sure someone has asked for this before).
May 09, 2007
janderson wrote:
> Pragma wrote:
> 
> Maybe something like C# user-definable attributes would help. (I'm sure someone has asked for this before).

I'm pretty sure I have on a few occasions. ;)

One way I can see this working is to use a custom pragma() - I think I managed to talk Gregor into trying it out in Rodin, at some point or another.  The suggestion isn't a personal bias, it's just that they're pretty much the ideal construct in D for supporting attributes.

struct ExceptionSafe{
  static ExceptionSafe opCall(){
    ExceptionSafe_this;
    return _this;
  }
}

// attach the ExceptionSafe attribute to the function f()
pragma(attr,ExceptionSafe()) void f(){
  /* do something */
}

But there are a few problems with using reflection to accomplish constraint checks.  The most obvious of which is that we're now checking things at runtime rather than at compile-time; so you have to run a full test suite in order to make sure you coded things up correctly.  Also, without being able to get the attributes for the current function, or even the calling function, there's no way to check the constraints without wrapping the call with a template.

The mess from using templates for this comes from the fact that the constraints can be thrown into a list in any order, so it defies the built-in specialization and overloading mechanisms provided by D.  If there were some way to specialize function declarations and calls, via an unordered property set (or by compile-time attributes), then it would be very easy to do.

-- 
- EricAnderton at yahoo
May 10, 2007
Pragma wrote:
> [...]
> One way I can see this working is to use a custom pragma() - I think I managed to talk Gregor into trying it out in Rodin, at some point or another.  The suggestion isn't a personal bias, it's just that they're pretty much the ideal construct in D for supporting attributes.
> 
> struct ExceptionSafe{
>   static ExceptionSafe opCall(){
>     ExceptionSafe_this;
>     return _this;
>   }
> }
> 
> // attach the ExceptionSafe attribute to the function f()
> pragma(attr,ExceptionSafe()) void f(){
>   /* do something */
> }
> [...]

Interestingly enough, this may well be only the second reasonable application of AOP that I've encountered. ;)  The problem here is that we want to perform a certain check *on every function*, but we don't want to make it *look* like we are performing the check.  Implementing these attributes as aspects actually makes a lot of sense.  I wonder whether D should try to support AOP somehow...

Dave
May 10, 2007
David B. Held wrote:
> Pragma wrote:
>> [...]
>> One way I can see this working is to use a custom pragma() - I think I managed to talk Gregor into trying it out in Rodin, at some point or another.  The suggestion isn't a personal bias, it's just that they're pretty much the ideal construct in D for supporting attributes.
>>
>> struct ExceptionSafe{
>>   static ExceptionSafe opCall(){
>>     ExceptionSafe_this;
>>     return _this;
>>   }
>> }
>>
>> // attach the ExceptionSafe attribute to the function f()
>> pragma(attr,ExceptionSafe()) void f(){
>>   /* do something */
>> }
>> [...]
> 
> Interestingly enough, this may well be only the second reasonable application of AOP that I've encountered. ;)  The problem here is that we want to perform a certain check *on every function*, but we don't want to make it *look* like we are performing the check.  Implementing these attributes as aspects actually makes a lot of sense.  I wonder whether D should try to support AOP somehow...
> 
> Dave

Well, this example is really more of an attempt to emulate C#'s attribute feature, which is really just to help enrich reflection.  I could easily see a pragma being used for AOP, though something like AOP (read: function-wrapping) should really be a first-class construct IMO.  I have no clue what that would look like, since there's so many different ways developers would expect AOP to work (i.e. explicit meshing of aspects, cross-cutting, etc).

You should drop a message in the "python style decorators thread".  It has morphed into an AOP for D discussion.

-- 
- EricAnderton at yahoo