Jump to page: 1 2
Thread overview
Extending typedefs
Jan 26, 2006
Deewiant
Jan 26, 2006
Carlos Smith
Jan 26, 2006
Deewiant
Jan 27, 2006
Ben Phillips
Jan 27, 2006
Craig Black
Jan 26, 2006
Craig Black
Jan 26, 2006
Oskar Linde
Jan 26, 2006
Craig Black
Jan 26, 2006
Deewiant
Jan 26, 2006
Craig Black
Jan 26, 2006
BCS
Jan 26, 2006
Craig Black
Jan 30, 2006
Oskar Linde
January 26, 2006
With strong typedefs, we can do type checking, like in the following canonical example:

---
typedef int Mass, Volume;

Mass x = 3;
Volume y = 4;

x = y; // error, cannot implicitly convert from Volume to Mass
---

But what we cannot do is the following:

---
Mass x;
Volume y;
Density z;

z = x / y;
---

Since x / y is an expression of type Mass (I believe), which can't be implicitly converted to Density. Thinking about this from physics's point of view, though, it should work: mass divided by volume is the definition of density.

Of course, this can be done with sufficient casting. But as we all know, casts are clumsy and make code get ugly very quickly.

Plus, things get really ugly when typedefing classes. See the following simple example, for instance:

---
class Vector {
	real x, y;
	this(real a, real b) { x = a; y = b; }
	Vector opMul(real n) { return new Vector(n * x, n * y); }
}
typedef Vector Velocity;

Velocity vel;
vel = cast(Velocity)(cast(Vector)vel * 2));
---

The inner cast is needed since otherwise DMD complains that "this for opMul needs to be type Vector not type Velocity". The outer cast, of, course, is to make the now-Vector (vel * 2) back into a Velocity. I wasn't even aware of this before starting to write this post. Even worse:

cast(Vector)vel *= 2;

Makes sense, right? Not to me, at least. This is one of the few instances were an lvalue can be a cast expression. Surely the "this" pointer in the class should be typedefed along with the class itself!

But even though I'd label the above as a bug (language or compiler, beats me), I
digress.

I'm proposing a syntax which would allow, for example, expressions of type (Mass / Volume) to be implicitly converted to Density. What I'm thinking of is along these lines:

typedef int Mass, Volume, Density;
typedef (Mass / Volume) Density;

So now, Density behaves like a normal typedef of an int until an expression of type (Mass / Volume) comes along, at which point a cast is no longer needed to convert the expression to type Density.

At best, the compiler could infer the other forms from the above, so that this is not needed:

typedef (Mass / Volume) Density;
typedef (Mass / Density) Volume;
typedef (Density * Volume) Mass;
typedef (Volume * Density) Mass;

But it's enough for me if the above works, whether it needs one line or four.

Comments on this or the "this" pointer casting?
January 26, 2006
"Deewiant" <deewiant.doesnotlike.spam@gmail.com> wrote in message news:dra43i$oec$1@digitaldaemon.com...
> With strong typedefs, we can do type checking, like in the following canonical
> example:
>
> ---
> typedef int Mass, Volume;
>
> Mass x = 3;
> Volume y = 4;
>
> x = y; // error, cannot implicitly convert from Volume to Mass
> ---
>
> But what we cannot do is the following:
>
> ---
> Mass x;
> Volume y;
> Density z;
>
> z = x / y;
> ---
>
> Since x / y is an expression of type Mass (I believe), which can't be implicitly
> converted to Density. Thinking about this from physics's point of view, though,
> it should work: mass divided by volume is the definition of density.
>
> Of course, this can be done with sufficient casting. But as we all know, casts
> are clumsy and make code get ugly very quickly.
>
> Plus, things get really ugly when typedefing classes. See the following simple
> example, for instance:
>
> ---
> class Vector {
> real x, y;
> this(real a, real b) { x = a; y = b; }
> Vector opMul(real n) { return new Vector(n * x, n * y); }
> }
> typedef Vector Velocity;
>
> Velocity vel;
> vel = cast(Velocity)(cast(Vector)vel * 2));
> ---
>
> The inner cast is needed since otherwise DMD complains that "this for opMul
> needs to be type Vector not type Velocity". The outer cast, of, course, is to
> make the now-Vector (vel * 2) back into a Velocity. I wasn't even aware of this
> before starting to write this post. Even worse:
>
> cast(Vector)vel *= 2;
>
> Makes sense, right? Not to me, at least. This is one of the few instances were
> an lvalue can be a cast expression. Surely the "this" pointer in the class
> should be typedefed along with the class itself!
>
> But even though I'd label the above as a bug (language or compiler, beats me), I
> digress.
>
> I'm proposing a syntax which would allow, for example, expressions of type (Mass
> / Volume) to be implicitly converted to Density. What I'm thinking of is along
> these lines:
>
> typedef int Mass, Volume, Density;
> typedef (Mass / Volume) Density;
>
> So now, Density behaves like a normal typedef of an int until an expression of
> type (Mass / Volume) comes along, at which point a cast is no longer needed to
> convert the expression to type Density.
>

This is an interesting ideas. But it needs some work to make it practical.

Does it means you would have to add a zillion typedef'initions to D ?
There are a lot of concepts in math, physics, ... defined in terms of numbers
who represent quantities.

Also, will you have to define:
   typedef (Mass / unsigned int ) Mass;
   typedef (Mass / negative int ) NegativeMass;
   ...

And, how will you define the different types for Surface.
   typedef ( ... ) Surface;     // for a circle.
   typedef ( ... ) Surface;    // for a square.
   typedef ( ... ) Surface;    // for a cube.

> At best, the compiler could infer the other forms from the above, so that this
> is not needed:
>
> typedef (Mass / Volume) Density;
> typedef (Mass / Density) Volume;
> typedef (Density * Volume) Mass;
> typedef (Volume * Density) Mass;
>
> But it's enough for me if the above works, whether it needs one line or four.
>

May be, it is better to have a rule, that says, that new typedef,
based on Basic Types of the language, inherit the properties of these
Basic Types.

And that means Mass can be divided by Volume because those are 2 integers.
And the result can be assigned to Density, because this is also an integer

> Comments on this or the "this" pointer casting? 

January 26, 2006
Carlos Smith wrote:
> Does it means you would have to add a zillion typedef'initions to D ? There are a lot of concepts in math, physics, ... defined in terms of numbers who represent quantities.

You would only have to add them if you wanted to make a strongly typed complete mathematics and physics library. <g> I'm not saying there have to be unique typedefs for every single thing, just that the feature could be useful.

> Also, will you have to define:
>    typedef (Mass / unsigned int ) Mass;
>    typedef (Mass / negative int ) NegativeMass;
>    ...

No, not necessarily. Only if I want to be really picky about the distinction between a mass and a negative mass. I'd say the only sane thing is just to do a normal "typedef int Mass" and then deal with negatives as necessary.

There is apparently such a thing as too strong typing. <g>

> And, how will you define the different types for Surface.
>    typedef ( ... ) Surface;     // for a circle.
>    typedef ( ... ) Surface;    // for a square.
>    typedef ( ... ) Surface;    // for a cube.
> 

typedef Surface Circle;
typedef Surface Square;
typedef Surface Cube;

They're completely independent of each other. _Maybe_ something like "typedef (Square * Square * Square) Cube" in addition to the above, but it seems to me that that would require some strange functionality in Surface.opMul(), so probably not.

It also seems to me that that should be done with classes and inheritance: circles and cubes are quite different things. Make a class (or interface) out of Surface and inherit as needed.

I'm not trying to replace the class mechanism here or anything. It's just that while it is also possible in my Mass/Volume/Density example to just make classes of the three and make them interoperate as they should, there are reasons why I'd much rather not:

* D doesn't allow overloading of =, so they would be pretty clumsy compared to
aliased integers (which is what I'd use without my suggested typedefs).
* I would basically be making an "abstract class Integer" which behaves just
like a normal int (but see above point), except that it can be subclassed.
* D isn't Ruby so I can't subclass int, which would deal with the above.

>> At best, the compiler could infer the other forms from the above, so
>> that this
>> is not needed:
>>
>> typedef (Mass / Volume) Density;
>> typedef (Mass / Density) Volume;
>> typedef (Density * Volume) Mass;
>> typedef (Volume * Density) Mass;
>>
>> But it's enough for me if the above works, whether it needs one line or four.
>>
> 
> May be, it is better to have a rule, that says, that new typedef, based on Basic Types of the language, inherit the properties of these Basic Types.
> 
> And that means Mass can be divided by Volume because those are 2 integers. And the result can be assigned to Density, because this is also an integer
> 

And the result can be assigned to Speed, because that's also an integer. But it makes no physical sense to apply Volume to Speed. Did I misunderstand or did you just describe the alias keyword?
January 26, 2006
I don't think typedefs are the solution to the problem that you are trying to solve.  C++ has libraries that have the capabilities that you propose (The SIUnits Library).  They use templates and operator overloading to enforce correctness when dealing with units.  Perhaps we can solve this problem without burdening Walter with another feature request.

-Craig

"Deewiant" <deewiant.doesnotlike.spam@gmail.com> wrote in message news:dra43i$oec$1@digitaldaemon.com...
> With strong typedefs, we can do type checking, like in the following
> canonical
> example:
>
> ---
> typedef int Mass, Volume;
>
> Mass x = 3;
> Volume y = 4;
>
> x = y; // error, cannot implicitly convert from Volume to Mass
> ---
>
> But what we cannot do is the following:
>
> ---
> Mass x;
> Volume y;
> Density z;
>
> z = x / y;
> ---
>
> Since x / y is an expression of type Mass (I believe), which can't be
> implicitly
> converted to Density. Thinking about this from physics's point of view,
> though,
> it should work: mass divided by volume is the definition of density.
>
> Of course, this can be done with sufficient casting. But as we all know,
> casts
> are clumsy and make code get ugly very quickly.
>
> Plus, things get really ugly when typedefing classes. See the following
> simple
> example, for instance:
>
> ---
> class Vector {
> real x, y;
> this(real a, real b) { x = a; y = b; }
> Vector opMul(real n) { return new Vector(n * x, n * y); }
> }
> typedef Vector Velocity;
>
> Velocity vel;
> vel = cast(Velocity)(cast(Vector)vel * 2));
> ---
>
> The inner cast is needed since otherwise DMD complains that "this for
> opMul
> needs to be type Vector not type Velocity". The outer cast, of, course, is
> to
> make the now-Vector (vel * 2) back into a Velocity. I wasn't even aware of
> this
> before starting to write this post. Even worse:
>
> cast(Vector)vel *= 2;
>
> Makes sense, right? Not to me, at least. This is one of the few instances
> were
> an lvalue can be a cast expression. Surely the "this" pointer in the class
> should be typedefed along with the class itself!
>
> But even though I'd label the above as a bug (language or compiler, beats
> me), I
> digress.
>
> I'm proposing a syntax which would allow, for example, expressions of type
> (Mass
> / Volume) to be implicitly converted to Density. What I'm thinking of is
> along
> these lines:
>
> typedef int Mass, Volume, Density;
> typedef (Mass / Volume) Density;
>
> So now, Density behaves like a normal typedef of an int until an
> expression of
> type (Mass / Volume) comes along, at which point a cast is no longer
> needed to
> convert the expression to type Density.
>
> At best, the compiler could infer the other forms from the above, so that
> this
> is not needed:
>
> typedef (Mass / Volume) Density;
> typedef (Mass / Density) Volume;
> typedef (Density * Volume) Mass;
> typedef (Volume * Density) Mass;
>
> But it's enough for me if the above works, whether it needs one line or four.
>
> Comments on this or the "this" pointer casting?


January 26, 2006
In article <dratih$1gmj$1@digitaldaemon.com>, Craig Black says...
>
>I don't think typedefs are the solution to the problem that you are trying to solve.  C++ has libraries that have the capabilities that you propose (The SIUnits Library).  They use templates and operator overloading to enforce correctness when dealing with units.  Perhaps we can solve this problem without burdening Walter with another feature request.

The feature requests needed for a SIUnits clone are:
- implicit function template instantiation
- assignment operator overloading (only for structs is enough)

/Oskar


January 26, 2006
> The feature requests needed for a SIUnits clone are:
> - implicit function template instantiation
> - assignment operator overloading (only for structs is enough)
>
> /Oskar

I know Walter wants to eventually add implicit function template instantiation, but as for assignment operator overloading, I don't know.  Do you think new typedef features would be easier to add to the compiler?  Do you think that they would facilitate a library with the capability of SIUnits?

-Craig


January 26, 2006
Craig Black wrote:
>> The feature requests needed for a SIUnits clone are:
>> - implicit function template instantiation
>> - assignment operator overloading (only for structs is enough)
>>
>> /Oskar
> 
> I know Walter wants to eventually add implicit function template instantiation, but as for assignment operator overloading, I don't know.  Do you think new typedef features would be easier to add to the compiler?  Do you think that they would facilitate a library with the capability of SIUnits?
> 
> -Craig
> 
> 

If it requires quite a lot of template "magic" or some such, while such a library would be useful it doesn't exactly solve the problem, since it'd be difficult to add new units. Of course, if it provides its own mechanism for doing just that, that's fine.

Unfortunately, porting such a library is probably a lot of work, even if we had the features that are, according to Oskar, required.

My typedef suggestion just struck me as the simplest solution. I am not a compiler writer, so I don't know whether that's correct or not, but in my opinion it would be simpler for the D programmers, at least, than messing around with templates. And, of course, different syntax, unless assignment operator overloading arrives.
January 26, 2006
> If it requires quite a lot of template "magic" or some such, while such a
> library would be useful it doesn't exactly solve the problem, since it'd
> be
> difficult to add new units. Of course, if it provides its own mechanism
> for
> doing just that, that's fine.

It does.  SIUnits is much more involved than what you propose.  It is based on the seven base units of the SI system:  length, mass, time, electric current, temperature, amount of substance, and luminous intensity.  All other SI units are merely combinations of one of these seven.  The templates have the smarts to know when you multiply length times length, you get length squared, or area.  If you divide length by time, you get velocity, etc.  There are an infinite number of combinations of these units and therefore an infinite number of unit types.  I believe such a system would be quite difficult to reproduce with typedefs as you propose.

> Unfortunately, porting such a library is probably a lot of work, even if
> we had
> the features that are, according to Oskar, required.

I am less concerned with the difficulty of such a task and more concerned with eventually attaining the most complete and elegant solution.

> My typedef suggestion just struck me as the simplest solution. I am not a
> compiler writer, so I don't know whether that's correct or not, but in my
> opinion it would be simpler for the D programmers, at least, than messing
> around
> with templates. And, of course, different syntax, unless assignment
> operator
> overloading arrives.

If someone else writes the template, and you merely have to use it, is that so bad?  SIUnits was probably a challenge to write, but using it is not that hard.

However, perhaps you are right.  But you are going to have to flesh out your idea more if it is to be on par with the capability of SIUnits.

-Craig


January 26, 2006
I have sketched some template code to see what it would take to do prity mutch exactly what you all are talking about. I thin that all that would be needed is implicet specilization of a function and allowing the return type of sutch a function to be determoned by the type of it's aruments.

Something like this:

template Unit(int L, int T, int M, int I, int K)
{
struct Unit
{
real v

Unit(L,T,M,I,K) opAdd(Unit(L,T,M,I,K) v2)
{
	Unit(L,T,M,I,K) ret;
	ret.v = v+v2.v;
	return ret;
}

// multiply this by an instance of Unit specialized for any values
// L,T,M,I&K come from this, l,t,m,i&k come from v2
Unit(L+l,T+t,M+m,I+i,K+k) opMul(Unit(l,t,m,i,k) v2)
{
	Unit(L+l,T+t,M+m,I+i,K+k) ret;
	ret.v = v*v2.v;
	return ret;
}
}
}

this has been brought up a number of times and I would rely like to see this kind of capacity added to D.


Craig Black wrote:
>>If it requires quite a lot of template "magic" or some such, while such a
>>library would be useful it doesn't exactly solve the problem, since it'd be
>>difficult to add new units. Of course, if it provides its own mechanism for
>>doing just that, that's fine.
> 
> 
> It does.  SIUnits is much more involved than what you propose.  It is based on the seven base units of the SI system:  length, mass, time, electric current, temperature, amount of substance, and luminous intensity.  All other SI units are merely combinations of one of these seven.  The templates 

IIRC it is possible to get away with 5 dimensions of units if you allow the Mole to be just a count and the candela to be power per area.

> have the smarts to know when you multiply length times length, you get length squared, or area.  If you divide length by time, you get velocity, etc.  There are an infinite number of combinations of these units and therefore an infinite number of unit types.  I believe such a system would be quite difficult to reproduce with typedefs as you propose.
> 
> 
>>Unfortunately, porting such a library is probably a lot of work, even if we had
>>the features that are, according to Oskar, required.
> 
> 
> I am less concerned with the difficulty of such a task and more concerned with eventually attaining the most complete and elegant solution.
> 
> 
>>My typedef suggestion just struck me as the simplest solution. I am not a
>>compiler writer, so I don't know whether that's correct or not, but in my
>>opinion it would be simpler for the D programmers, at least, than messing around
>>with templates. And, of course, different syntax, unless assignment operator
>>overloading arrives.
> 
> 
> If someone else writes the template, and you merely have to use it, is that so bad?  SIUnits was probably a challenge to write, but using it is not that hard.
> 
> However, perhaps you are right.  But you are going to have to flesh out your idea more if it is to be on par with the capability of SIUnits.
> 
> -Craig 
> 
> 
January 26, 2006
"BCS" <BCS_member@pathlink.com> wrote in message news:drbgor$21oo$1@digitaldaemon.com...
>I have sketched some template code to see what it would take to do prity mutch exactly what you all are talking about. I thin that all that would be needed is implicet specilization of a function and allowing the return type of sutch a function to be determoned by the type of it's aruments.
>
> Something like this:
>
> template Unit(int L, int T, int M, int I, int K)
> {
> struct Unit
> {
> real v
>
> Unit(L,T,M,I,K) opAdd(Unit(L,T,M,I,K) v2)
> {
> Unit(L,T,M,I,K) ret;
> ret.v = v+v2.v;
> return ret;
> }
>
> // multiply this by an instance of Unit specialized for any values
> // L,T,M,I&K come from this, l,t,m,i&k come from v2
> Unit(L+l,T+t,M+m,I+i,K+k) opMul(Unit(l,t,m,i,k) v2)
> {
> Unit(L+l,T+t,M+m,I+i,K+k) ret;
> ret.v = v*v2.v;
> return ret;
> }
> }
> }
>
> this has been brought up a number of times and I would rely like to see this kind of capacity added to D.

I agree.  This would be a worthwhile addition to D's template capabilities. Why do you think Oskar suggested that assignment operator overloading would be required?

-Craig


« First   ‹ Prev
1 2