literals

so so at so.do
Sun Mar 28 13:34:56 PDT 2010


On Mon, 29 Mar 2010 00:46:20 +0400, Don <nospam at nospam.com> wrote:

> so wrote:
>> Hello Don, finally!
>>  It is hard to explain yourself when you don't know the people you talk  
>> have numeric coding background.
>> Since we know you have done much numeric and generic coding, it will be  
>> enough for me if you understand what i mean/ask/want,
>> and say what i am talking is ridiculous, or think that i am trolling,  
>> just say so and i shut up! :)
>
> You're definitely not trolling! I'm not 100% sure of which issue you're  
> referring too, but I'm aware of a few, for example:
>
> (1) Converting a floating point literal into a double literal is usually  
> not lossless.
> 0.5f, 0.5, and 0.5L are all exactly the same number, since they are  
> exactly representable.
> But 0.1 is not the same as 0.1L.
> So it's a bit odd that this silent lossless conversion is taking place.
> It does have a very strong precedent from C, however.
>
> (2) The interaction between implicit casting and template parameters is  
> quite poor. Eg, the fact that '0' is an int, not a floating point type,  
>   means that something simple like:
>   add(T)(T x) if (isFloatingPoint!(T))
> doesn't work properly. It is not the same as:
> add(real x)
> since it won't allow add(0).
>
> Which is pretty annoying. Why can't 0 just mean zero???

At the beginning the question in my mind was, why can't we do this the way  
it works in math :

[Real numbers] contains [Integers] contains [Natural numbers]

So, when a compiler see 0, which is the element of all above, it should  
classify it as :
1st degree. [floating point type, integer, natural number]
When it encounters say, -3, it will be :
2nd degree. [floating point type and integer]
And finally when it encounters something like 4.0, it will be :
3rd degree. [floating point type]

With these in mind, the prototype :

T foo(T)(T m) {}, should be able to take all three degrees of types above.

We go abit further and see what it actually is :

T foo(T)(T m) {
	T n = m * 5 - 4 * 7 / 2; // numbers belongs all the systems above, this  
line should work for every T
	T k = n / 20; // same.
	return n + k; // same.
}

"T n = m * 5 - 4 * 7 / 2;"
m is here in the type of T,
* operator has a generic operand 5, convert it to T, if you can't, pop  
error.
- operator has a generic operand (4 * 7 / 2), expect it in the and keep  
parsing.

Again, in the code above, none of the constants is a native type, as in 5  
is not int, it is a generic constant which belongs all systems above.
What this means?

calling foo(0.0f) is actually :
float foo(float m) {
	float n = m * 5.0f - 4.0f * 7.0f / 2.0f;
	float k = n / 20.0f;
	return n + k;
}

m is here float and operation * has a generic operand

There wasn't a single implicit cast and the code was perfectly generic.
calling foo(0) will pass the "if(isFloatingPoint!(T))" contract, since 0  
belongs to all,
but compiler will be unable to resolve the final type which is to be  
instantiated.

But coming with something like this would be suicide since i already got  
enough treatment for the lighter syntax :P
Sorry for the long post!

Thanks.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/



More information about the Digitalmars-d mailing list