www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Typedef blocks

reply pragma <EricAnderton at yahoo dot com> <pragma_member pathlink.com> writes:
All apologies if this has been suggested before.

I think it would be useful to be able to extend basic types using typedef as an
optional block, with struct-like semantics inside.  

Take the following:

# typedef char[][char[]] AttributeSet;

In order to organize access to this type I have to write several functions to
better encapsulate all the repeated bits that I use. 

# char[] getAttribute(AttributeSet attribs,char[] name);
# char[] getRequiredAttribute(AttributeSet attribs,char[] name);

The attribs would be set using the type's built-in array indexing.

# AttributeSet set;
# set["name"] = "foo";
# set["color"] = "red";

I could write a class to emulate the char[char[]] type, and expose the needed
methods.  This seems like persisting a bad habit and an equally bad design as,
I'm just basically rewriting an existing type.  

What I'd like to be able to do is *extend* the existing type (char[][char[]]) by
adding some methods to it, which isn't possible because it's neither a struct
nor a class.

-- Proposal --

Ideally i'd like to be able to use a primitive as a base for a struct or a
class, but that won't work for a whole host of reasons.  Instead, I'd like to be
able to attach a scope to a typedef, which contains only static data and methods
that implicitly work against the base type.

# typedef char[][char[]] AttributeSet{
#     char[] getAttribute(char[] name){
#         return(this[name]);
#     }
#     char[] getRequiredAttribute(char[] name){
#         char[] value = this[name];
#         if(!value) throw new Error(name ~ " is required.");
#         return(value);
#     }
# }

This would allow AttributeSet, for example, to behave as a "char[][char[]]"
while having methods that are passed the instance implicitly via "this".  

# AttributeSet set;
# set["name"] = "foo";
# set["color"] = "red";
# 
# // elsewhere...
# char[] foo = set.getAttribute("foo");
# char[] bar = set.getRequiredAttribute("red");


By this, we have a set of methods that are intended to work with one primitive
type, and are scoped as such.  Yet we avoid the overhead of a class, and the
(laborious) rewriting of a primitive's capabilities in a class or struct.  

- Pragma
Aug 03 2004
next sibling parent Regan Heath <regan netwin.co.nz> writes:
Hows this...

import std.string;

class AttributeSetT(Value, Key)
{
	Value getAttribute(Key key)
	{
		return data[key];
	}
	
	Value getRequiredAttribute(Key key)
	{
		Value v = data[key];
		if (v == v.init) {
			char[] keyname;
			
			if (typeid(typeof(key)) === typeid(char[])) keyname = key;
			else keyname = std.string.toString(key);
			
			throw new Error(keyname ~ " is required.");
		}
		return v;
	}
	
	Value opIndex(Key key)
	{
		return data[key];
	}
	
	Value opIndexAssign(Value val, Key key)
	{
		data[key] = val;
		return data[key];
	}
	
private:
	Value[Key] data;
}

typedef AttributeSetT!(char[],char[]) Set1;
typedef AttributeSetT!(int,char[])    Set2;
typedef AttributeSetT!(float,int)     Set3;

void main()
{
	Set1 a1 = new Set1();
	char[] v1;
	
	Set2 a2 = new Set2();
	int v2;
	
	Set3 a3 = new Set3();
	float v3;
	
	
	printf("SET1 start\n");
	a1["a"] = "1";
	v1 = a1.getAttribute("a");
	printf("a is %.*s\n",v1);	
	try { v1 = a1.getRequiredAttribute("b");}
	catch(Error e) { e.print(); }	
	printf("SET1 done\n\n");
	
	printf("SET2 start\n");
	a2["a"] = 1;
	v2 = a2.getAttribute("a");
	printf("a is %d\n",v2);	
	try { v2 = a2.getRequiredAttribute("b");}
	catch(Error e) { e.print(); }	
	printf("SET2 done\n\n");

	printf("SET3 start\n");
	a3[1] = 2.0;
	v3 = a3.getAttribute(1);
	printf("1 is %f\n",v3);	
	try { v3 = a3.getRequiredAttribute(2);}
	catch(Error e) { e.print(); }	
	printf("SET3 done\n\n");
}

Regan

On Wed, 4 Aug 2004 01:47:17 +0000 (UTC), pragma <EricAnderton at yahoo dot 
com pragma_member pathlink.com> wrote:

 All apologies if this has been suggested before.

 I think it would be useful to be able to extend basic types using 
 typedef as an
 optional block, with struct-like semantics inside.

 Take the following:

 # typedef char[][char[]] AttributeSet;

 In order to organize access to this type I have to write several 
 functions to
 better encapsulate all the repeated bits that I use.

 # char[] getAttribute(AttributeSet attribs,char[] name);
 # char[] getRequiredAttribute(AttributeSet attribs,char[] name);

 The attribs would be set using the type's built-in array indexing.

 # AttributeSet set;
 # set["name"] = "foo";
 # set["color"] = "red";

 I could write a class to emulate the char[char[]] type, and expose the 
 needed
 methods.  This seems like persisting a bad habit and an equally bad 
 design as,
 I'm just basically rewriting an existing type.

 What I'd like to be able to do is *extend* the existing type 
 (char[][char[]]) by
 adding some methods to it, which isn't possible because it's neither a 
 struct
 nor a class.

 -- Proposal --

 Ideally i'd like to be able to use a primitive as a base for a struct or 
 a
 class, but that won't work for a whole host of reasons.  Instead, I'd 
 like to be
 able to attach a scope to a typedef, which contains only static data and 
 methods
 that implicitly work against the base type.

 # typedef char[][char[]] AttributeSet{
 #     char[] getAttribute(char[] name){
 #         return(this[name]);
 #     }
 #     char[] getRequiredAttribute(char[] name){
 #         char[] value = this[name];
 #         if(!value) throw new Error(name ~ " is required.");
 #         return(value);
 #     }
 # }

 This would allow AttributeSet, for example, to behave as a 
 "char[][char[]]"
 while having methods that are passed the instance implicitly via "this".

 # AttributeSet set;
 # set["name"] = "foo";
 # set["color"] = "red";
 #
 # // elsewhere...
 # char[] foo = set.getAttribute("foo");
 # char[] bar = set.getRequiredAttribute("red");


 By this, we have a set of methods that are intended to work with one 
 primitive
 type, and are scoped as such.  Yet we avoid the overhead of a class, and 
 the
 (laborious) rewriting of a primitive's capabilities in a class or struct.

 - Pragma

-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 03 2004
prev sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}




"pragma" <EricAnderton at yahoo dot compragma_member pathlink.com> wrote in
message news:cepf75$1qi0$1 digitaldaemon.com...
 All apologies if this has been suggested before.

 I think it would be useful to be able to extend basic types using typedef

 optional block, with struct-like semantics inside.

 Take the following:

 # typedef char[][char[]] AttributeSet;

 In order to organize access to this type I have to write several functions

 better encapsulate all the repeated bits that I use.

 # char[] getAttribute(AttributeSet attribs,char[] name);
 # char[] getRequiredAttribute(AttributeSet attribs,char[] name);

 The attribs would be set using the type's built-in array indexing.

 # AttributeSet set;
 # set["name"] = "foo";
 # set["color"] = "red";

 I could write a class to emulate the char[char[]] type, and expose the

 methods.  This seems like persisting a bad habit and an equally bad design

 I'm just basically rewriting an existing type.

 What I'd like to be able to do is *extend* the existing type

 adding some methods to it, which isn't possible because it's neither a

 nor a class.

 -- Proposal --

 Ideally i'd like to be able to use a primitive as a base for a struct or a
 class, but that won't work for a whole host of reasons.  Instead, I'd like

 able to attach a scope to a typedef, which contains only static data and

 that implicitly work against the base type.

 # typedef char[][char[]] AttributeSet{
 #     char[] getAttribute(char[] name){
 #         return(this[name]);
 #     }
 #     char[] getRequiredAttribute(char[] name){
 #         char[] value = this[name];
 #         if(!value) throw new Error(name ~ " is required.");
 #         return(value);
 #     }
 # }

 This would allow AttributeSet, for example, to behave as a

 while having methods that are passed the instance implicitly via "this".

 # AttributeSet set;
 # set["name"] = "foo";
 # set["color"] = "red";
 #
 # // elsewhere...
 # char[] foo = set.getAttribute("foo");
 # char[] bar = set.getRequiredAttribute("red");


 By this, we have a set of methods that are intended to work with one

 type, and are scoped as such.  Yet we avoid the overhead of a class, and

 (laborious) rewriting of a primitive's capabilities in a class or struct.

 - Pragma

Aug 04 2004
next sibling parent reply pragma <EricAnderton at yahoo dot com> <pragma_member pathlink.com> writes:
In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

*stunned* Wow... I honestly didn't think that would work. So D implicitly passes the first arg if it's a match for the 'object' to the left? Nifty. This gets really close to the mark of my proposal. What it lacks is the kind of first class method-to-type grouping that classes and structs get. :) Regan also posted this beautiful template that does the job well. That's a good solution too, but it would require a developer to rewrite every facet that the primitive type already provides. Its the duplication of effort that I would love to see replaced since that is typically a Bad Thing(tm). Using your suggestion, I tried to (once again) create a multicast delegate (event). # alias WindowEventDelegate void delegate(char[]); # typedef WindowEventDelegate[] WindowEvent; # # void opCall(char[] reason){ # foreach(WindowEventDelegate d; this){ # d(reason); # } # } But of course we cannot override operators in the global scope, so /something/ is still needed. But it does work as long as you invoke using .opCall verbatim. - Pragma
Aug 04 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"pragma" <EricAnderton at yahoo dot compragma_member pathlink.com> wrote in
message news:ceqq0o$2oof$1 digitaldaemon.com...
 In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

*stunned*

indeed!
 Wow... I honestly didn't think that would work.  So D implicitly passes

 first arg if it's a match for the 'object' to the left?  Nifty.  This gets

Only if the first arg is an array!
 really close to the mark of my proposal.  What it lacks is the kind of

 class method-to-type grouping that classes and structs get. :)

What about soemthing like this: template AttributeSet(T,V) { typedef T[V] AttributeSet; T getAttribute(AttributeSet a, V x) { writefln(x); return a[x]; } } void main () { mixin AttributeSet!(char[],char[]) AttributeSetX; AttributeSetX.AttributeSet set; set["name"] = "foo"; set["color"] = "red"; set.getAttribute("BLA"); }
 Regan also posted this beautiful template that does the job well.  That's

 solution too, but it would require a developer to rewrite every facet that

 primitive type already provides.  Its the duplication of effort that I

 love to see replaced since that is typically a Bad Thing(tm).

 Using your suggestion, I tried to (once again) create a multicast delegate
 (event).

 # alias WindowEventDelegate void delegate(char[]);
 # typedef WindowEventDelegate[] WindowEvent;
 #
 # void opCall(char[] reason){
 #     foreach(WindowEventDelegate d; this){
 #         d(reason);
 #     }
 # }

 But of course we cannot override operators in the global scope, so

 is still needed.  But it does work as long as you invoke using .opCall

Or maby a class solution would be best?
 - Pragma

Aug 04 2004
parent reply pragma <EricAnderton at yahoo dot com> <pragma_member pathlink.com> writes:
In article <cequ4v$312p$1 digitaldaemon.com>, Ivan Senji says...
What about soemthing like this:

template AttributeSet(T,V)
{
     typedef T[V] AttributeSet;

     T getAttribute(AttributeSet a, V x)
     {
          writefln(x);
          return a[x];
     }
}

void main ()
{
 mixin AttributeSet!(char[],char[]) AttributeSetX;
 AttributeSetX.AttributeSet set;
 set["name"] = "foo";
 set["color"] = "red";
 set.getAttribute("BLA");
}

Or better yet: alias AttributeSet!(char[],char[]).AttributeSet ASet; Aset set; Which should make things a little more transparent, especially when passing it around from function to function.
 # alias WindowEventDelegate void delegate(char[]);
 # typedef WindowEventDelegate[] WindowEvent;
 #
 # void opCall(char[] reason){
 #     foreach(WindowEventDelegate d; this){
 #         d(reason);
 #     }
 # }

 But of course we cannot override operators in the global scope, so

 is still needed.  But it does work as long as you invoke using .opCall

Or maby a class solution would be best?

I'd agree, except in order to do the same /exact/ thing as my proposed typedef block, you're looking at reproducing the behavior in roughly 12 methods and members that are already available in char[char[]]. I know that using a class is the best way ahead for now, but extending typedef this way leads to much more maintainable code IMO. - Pragma
Aug 04 2004
parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"pragma" <EricAnderton at yahoo dot compragma_member pathlink.com> wrote in
message news:cer1f8$5kj$1 digitaldaemon.com...
 In article <cequ4v$312p$1 digitaldaemon.com>, Ivan Senji says...
What about soemthing like this:

template AttributeSet(T,V)
{
     typedef T[V] AttributeSet;

     T getAttribute(AttributeSet a, V x)
     {
          writefln(x);
          return a[x];
     }
}

void main ()
{
 mixin AttributeSet!(char[],char[]) AttributeSetX;
 AttributeSetX.AttributeSet set;
 set["name"] = "foo";
 set["color"] = "red";
 set.getAttribute("BLA");
}

Or better yet: alias AttributeSet!(char[],char[]).AttributeSet ASet; Aset set;

This is what i did at first too, but there wasn't a way to call set.getAttrubute in a simple way! Or have you found a way!
 Which should make things a little more transparent, especially when

 around from function to function.

 # alias WindowEventDelegate void delegate(char[]);
 # typedef WindowEventDelegate[] WindowEvent;
 #
 # void opCall(char[] reason){
 #     foreach(WindowEventDelegate d; this){
 #         d(reason);
 #     }
 # }

 But of course we cannot override operators in the global scope, so

 is still needed.  But it does work as long as you invoke using .opCall

Or maby a class solution would be best?

I'd agree, except in order to do the same /exact/ thing as my proposed

 block, you're looking at reproducing the behavior in roughly 12 methods

 members that are already available in char[char[]].  I know that using a

 is the best way ahead for now, but extending typedef this way leads to

 maintainable code IMO.

 - Pragma

Aug 04 2004
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

Holy cow! That works? Fantastic :) My evil mind is already reeling with the possibilities. I'll have to chalk that one up as yet another often requested C++ feature that D already has. Sean
Aug 04 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <cer02j$2pe$1 digitaldaemon.com>, Sean Kelly says...
In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

Holy cow! That works? Fantastic :) My evil mind is already reeling with the possibilities. I'll have to chalk that one up as yet another often requested C++ feature that D already has.

Quick update: this only works for array types. If possible, I'd like to request to it work for all primitive types. Sean
Aug 04 2004
next sibling parent pragma <EricAnderton at yahoo dot com> <pragma_member pathlink.com> writes:
In article <cergqb$g58$1 digitaldaemon.com>, Sean Kelly says...
In article <cer02j$2pe$1 digitaldaemon.com>, Sean Kelly says...
In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

Holy cow! That works? Fantastic :) My evil mind is already reeling with the possibilities. I'll have to chalk that one up as yet another often requested C++ feature that D already has.

Quick update: this only works for array types. If possible, I'd like to request to it work for all primitive types.

Walter, I'd like to second this, as I wouldn't mind seeing functions work like this for _all_ primitive types as well. To recap: # int sum(int[] list){ # int result = 0; # foreach(int i; list) result += i; # return result; # } # # int abs(int value){ # return value < 0 ? -value : value; # } # # void main(){ # int[] list; # int value; # value = list.sum(); // works great! (thank you Walter) # value.abs(); // compiler complains (see below) :( # } test.d(15): no property 'abs' for type 'int' Also, the ability to override operators for primitives in a similar way would really expand the role of primitive types in D. # void opCall(int[] value){ # } # # void main(){ # int value[]; # value.opCall(); // works, but not what was intended # value(); // compiler complains (below) # } test.d(7): function expected before (), not 'int[]' - Pragma
Aug 04 2004
prev sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:cergqb$g58$1 digitaldaemon.com...
 In article <cer02j$2pe$1 digitaldaemon.com>, Sean Kelly says...
In article <ceq4g5$236p$1 digitaldaemon.com>, Ivan Senji says...
I don't know if this helps:


typedef char[][char[]] AttributeSet;

char[] getAttribute(AttributeSet a, char[] x)
{
    //do something
}

void main ()
{
     AttributeSet set;
     set["name"] = "foo";
     set["color"] = "red";
     set.getAttribute("BLA");
}

Holy cow! That works? Fantastic :) My evil mind is already reeling


possibilities.  I'll have to chalk that one up as yet another often


C++ feature that D already has.

Quick update: this only works for array types. If possible, I'd like to

 to it work for all primitive types.

When i first learned about this feature i was also little dissapointed about it working only for arrays, and i had the same request, but over time i realized that although this could be useful for all primitive types, it is most useful for arrays.
 Sean

Aug 04 2004