digitalmars.D - literals
- so (8/8) Mar 28 2010 Hello, after a little discussion on D.learn, i better ask this here sinc...
- Robert Clipsham (5/11) Mar 28 2010 This should help you understand:
- so (10/23) Mar 28 2010 You misunderstood the question, i didn't ask "what", i asked "why" :)
- bearophile (4/6) Mar 28 2010 A possible answer: because D2 has no polysemus literals yet :-)
- so (7/13) Mar 28 2010 That also means, you can't write a generic code in a C derived language ...
- Fawzi Mohamed (29/40) Mar 28 2010 no the answer is more complex:
- so (30/58) Mar 28 2010 I don't think it is that complex, if it is please point me.
- so (12/12) Mar 28 2010 One more thing about the code :
- Fawzi Mohamed (8/21) Mar 28 2010 yes what about it what should the compiler do? read your mind? the
- so (9/13) Mar 28 2010 When you divide 1.0 / 5, compilers warns or implicitly converts "5" to a...
- Steven Schveighoffer (9/20) Mar 28 2010 What you want is implicit function template instantiation based on the
- so (21/29) Mar 28 2010 Hello!
- Steven Schveighoffer (25/54) Mar 28 2010 What you are asking for is a template instantiation that depends on
- so (17/78) Mar 28 2010 I don't think a language/compiler should make premature decisions when a...
- Steven Schveighoffer (24/71) Mar 29 2010 It has to make a decision on literals, or else you can't use them withou...
- Fawzi Mohamed (6/18) Mar 29 2010 charset=US-ASCII;
- so (51/54) Mar 29 2010 Could you please write the equivalent D code for generic inv function?
- Steven Schveighoffer (22/41) Mar 29 2010 OK, I see the issue now. The syntax for declaring that a literal is the...
- so (9/14) Mar 29 2010 It would be nice indeed!
- Fawzi Mohamed (22/47) Mar 29 2010 well as you said in mathematics a Natural number is also an Integer
- so (10/21) Mar 29 2010 Finally i am able to explain it with 2 words, Hindley Milner :)
- Fawzi Mohamed (8/33) Mar 29 2010 ehm actually Hindley Milner is not enough for what you requested, it
- Fawzi Mohamed (21/88) Mar 28 2010 or give you the "default" precision. And note that this problem is not
- so (26/45) Mar 28 2010 float faster and use half of double, that is not a valid argument, and i...
- Fawzi Mohamed (18/62) Mar 28 2010 really the compiler cannot parse your function, and I can't either, to
- so (28/42) Mar 28 2010 So you are saying a compiler is unable to parse this :
- Fawzi Mohamed (21/33) Mar 28 2010 you know with someone that uses a clearly fake email, does not bother
- so (4/40) Mar 28 2010 --
- Justin Johansson (4/12) Mar 28 2010 You meant "polysemous", right? :-)
- so (12/18) Mar 28 2010 What is interesting about it is, DMD already has the solution, and it is...
- Don (11/37) Mar 28 2010 It's a bit surprising how D treats numeric literals. Although (say) 2.1
- so (11/43) Mar 28 2010 Hello Don, finally!
- Don (18/26) Mar 28 2010 You're definitely not trolling! I'm not 100% sure of which issue you're
- superdan (12/40) Mar 28 2010 he wanna 1.0 to adapt to T. i'm sayin' if u pass float to inv 1.0 gotta ...
- superdan (2/3) Mar 28 2010 dats 1.0F not 10.F. shit. but im sure u peoples feel me.
- so (47/72) Mar 28 2010 At the beginning the question in my mind was, why can't we do this the w...
- so (6/9) Mar 28 2010 and ignore this line :)
- Fawzi Mohamed (19/93) Mar 28 2010 why do you see implicit cast as bad? for me the change from 5 to 5.0f
- so (30/52) Mar 28 2010 Hello!
- Fawzi Mohamed (41/67) Mar 28 2010 ok if you have a real message, I am sorry to have been so harsh, I was
- so (18/74) Mar 28 2010 D is the best language i have seen, and that is why i am here.
- Walter Bright (9/14) Mar 28 2010 It depends. The D compiler internally stores all floating point constant...
- Fawzi Mohamed (6/22) Mar 28 2010 ok good that is actually how I though, so that cast(T)x is indeed the
- Don (10/29) Mar 29 2010 There's some oddities.
- Fawzi Mohamed (12/39) Mar 29 2010 good to have the numerics expert look into this.
Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On 28/03/10 12:02, so wrote:Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks!This should help you understand: http://digitalmars.com/d/2.0/lex.html#integerliteral If you scroll down from there you'll also see what counts as a floating point literal and why.
Mar 28 2010
You misunderstood the question, i didn't ask "what", i asked "why" :) I know what are the literals. Again the question is... Why "3" is "especially" an "int=int32"? Why "0.3" is "especially" a "double=float64"? Thanks. On Sun, 28 Mar 2010 16:08:27 +0400, Robert Clipsham <robert octarineparrot.com> wrote:On 28/03/10 12:02, so wrote:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks!This should help you understand: http://digitalmars.com/d/2.0/lex.html#integerliteral If you scroll down from there you'll also see what counts as a floating point literal and why.
Mar 28 2010
so:Why "3" is an int? Why "0.3" is a double?A possible answer: because D2 has no polysemus literals yet :-) Bye, bearophile
Mar 28 2010
That also means, you can't write a generic code in a C derived language "by definition", right? Thanks. On Sun, 28 Mar 2010 16:30:28 +0400, bearophile <bearophileHUGS lycos.com> wrote:so:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/Why "3" is an int? Why "0.3" is a double?A possible answer: because D2 has no polysemus literals yet :-) Bye, bearophile
Mar 28 2010
On 28-mar-10, at 13:39, so wrote:That also means, you can't write a generic code in a C derived language "by definition", right? Thanks. On Sun, 28 Mar 2010 16:30:28 +0400, bearophile <bearophileHUGS lycos.comno the answer is more complex: for integers normally the smallest possible integral type is used (but not exactly int wins in some occasions, check the exact rules) and then implicit conversion can take place. The rules are such that it should do what one means most times (so conversion to long or uint is ok), but there are some pitfalls, often associated to conversion to unsigned (that I find useful though, even if it can lead to bugs in some occasions, and there are some reasons to like infinite integers as some languages have). Still if you write a very large number it is a long for example. floating point numbers are a bit different (because they are always approximated), but the philosophy is similar. The absence polysemus literals is not a problem in my opinion, you can avoid that having good implicit casting rules. unexpected results normally happen just when you have something very ambiguous. For example if you have an overloaded function and you call it with a literal then in *any* language you need to decide which default value has the literal (to decide with which type to start before looking at implicit conversions). D (like C) chooses int for for 3, and double for 0.3 (the latter I suppose for C compatibility and efficiency reasons, because one could argue that real would be a "safer" choice). Yes there are some dark corners, but I don't see things that make generic programming impossible. Maybe if you would say what you try to do you would receive more meaningful answers. Fawziwrote:so:Why "3" is an int? Why "0.3" is a double?A possible answer: because D2 has no polysemus literals yet :-)
Mar 28 2010
I don't think it is that complex, if it is please point me. It is simple math. "3" the number belongs to many number systems. Making default int (actually "signed int") is the source of complexity, same goes for "0.3". For function overload case: foo(float) foo(double) foo(real) If i call the overloaded functions above with foo(0.3), since i haven't explicitly stated (in C world, i explicitly stated it is double) which function i refer, it is my fault, compiler should warn/error or give me the highest precision available, you name it. The reason might be compatibility but i am unable to see any efficiency there. What i want is simple, in a generic code, which in this case a template, i should be able to write the code below with "zero" implicit casts. T inv(T m)() { return 1.0 / m; } What do you see in this code? What the user wants? User explicitly stated that he wants "1.0" in the type of T. So when "T" is float, give the float version of "1.0". If i am not mistaken, this is actually how constant folding actually works, see the page. Thanks. On Sun, 28 Mar 2010 17:20:41 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:no the answer is more complex: for integers normally the smallest possible integral type is used (but not exactly int wins in some occasions, check the exact rules) and then implicit conversion can take place. The rules are such that it should do what one means most times (so conversion to long or uint is ok), but there are some pitfalls, often associated to conversion to unsigned (that I find useful though, even if it can lead to bugs in some occasions, and there are some reasons to like infinite integers as some languages have). Still if you write a very large number it is a long for example. floating point numbers are a bit different (because they are always approximated), but the philosophy is similar. The absence polysemus literals is not a problem in my opinion, you can avoid that having good implicit casting rules. unexpected results normally happen just when you have something very ambiguous. For example if you have an overloaded function and you call it with a literal then in *any* language you need to decide which default value has the literal (to decide with which type to start before looking at implicit conversions). D (like C) chooses int for for 3, and double for 0.3 (the latter I suppose for C compatibility and efficiency reasons, because one could argue that real would be a "safer" choice). Yes there are some dark corners, but I don't see things that make generic programming impossible. Maybe if you would say what you try to do you would receive more meaningful answers. Fawzi-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
One more thing about the code : T inv(T m)() { return 1.0 / m; } What if we call inv(5)? This is an error, why? - Function explicitly states that the parameter is a floating point type. - Operations between floating point types and integers result a floating point type , as you see from the return type, code returns the type of parameter, in this case an integer. Thanks.
Mar 28 2010
On 28-mar-10, at 15:03, so wrote:One more thing about the code : T inv(T m)() { return 1.0 / m; } What if we call inv(5)?yes what about it what should the compiler do? read your mind? the code that I gave returns 0This is an error, why? - Function explicitly states that the parameter is a floating point type.how?- Operations between floating point types and integers result a floating point typethis is the case, as you see from the return type, code returns the type of parameter, in this case an integer.yes you can write a template that automatically "upconverts" to float, but I don't think that is the correct thing for a default thing to do, why do you alway want to have floats as result?Thanks.
Mar 28 2010
On Sun, 28 Mar 2010 18:18:20 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:how?When you divide 1.0 / 5, compilers warns or implicitly converts "5" to a floating point type, am i wrong? I told you what i want, remember "zero implicit cast"yes you can write a template that automatically "upconverts" to float, but I don't think that is the correct thing for a default thing to do, why do you alway want to have floats as result?I don't always want float as result, but check the function again. What happens there? "1.0 / m" which will result a floating point type, what code suggests is, that this type will be "T" -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On Sun, 28 Mar 2010 09:26:43 -0400, so <so so.do> wrote:On Sun, 28 Mar 2010 18:18:20 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:What you want is implicit function template instantiation based on the return type. D doesn't do that, it doesn't even allow overloading based on the return type. However, you can infer the return type using auto: auto inv(T)(T m) { return 1.0/m; } -Stevehow?When you divide 1.0 / 5, compilers warns or implicitly converts "5" to a floating point type, am i wrong? I told you what i want, remember "zero implicit cast"yes you can write a template that automatically "upconverts" to float, but I don't think that is the correct thing for a default thing to do, why do you alway want to have floats as result?I don't always want float as result, but check the function again. What happens there? "1.0 / m" which will result a floating point type, what code suggests is, that this type will be "T"
Mar 28 2010
What you want is implicit function template instantiation based on the return type. D doesn't do that, it doesn't even allow overloading based on the return type. However, you can infer the return type using auto: auto inv(T)(T m) { return 1.0/m; } -SteveHello! I guess, i am unable to express myself. In code : T inv(T)(T m) { return 1.0/m; } If we forget the rules of default literals that C derived languages have, just for a second. And enforce our own little rule. - no implicit casts With this in mind this code says; i gave you T, give me T in return, perfectly clear i guess? Now when you call the function with a floating point, real, double, float..., you will get what you asked for. Now what about other types? Say you call it with a non floating type, when compiler tries to divide the first thing it will encounter that one of two elements of the operation is a non-float, since we enforced a rule, it gives warning or error. Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On Sun, 28 Mar 2010 14:29:52 -0400, so <so so.do> wrote:What you are asking for is a template instantiation that depends on instantiating itself. How about a function like this? void foo(int x); T inv(T)(T m) { foo(m); return 1.0/m; } How do you know what type to use for T? It's simple when you make inv a one-liner, there is only one thing to look at. But as you start making the function more complex, then it's impossible to tell what the user actually wants. In this instance, T must be implicitly convertable to int, but also must be a floating point type. Clearly there is an error here, but where is it? This is called ambiguity, and to avoid it, the compiler makes a decision, right or wrong, based on the literal used to call the function. It expects you, the user, to help out when it doesn't make the right one. I don't think it's too much to ask. It's simply a tradeoff between being an all-powerful oracle-like compiler and being a simple-to-write compiler. What the compiler sees when deciding to instantiate is this: T inv(T)(T m) {...} And it makes a decision. If you have a problem with writing inv(5.0) instead of inv(5), then maybe D just isn't for you. -SteveWhat you want is implicit function template instantiation based on the return type. D doesn't do that, it doesn't even allow overloading based on the return type. However, you can infer the return type using auto: auto inv(T)(T m) { return 1.0/m; } -SteveHello! I guess, i am unable to express myself. In code : T inv(T)(T m) { return 1.0/m; } If we forget the rules of default literals that C derived languages have, just for a second. And enforce our own little rule. - no implicit casts With this in mind this code says; i gave you T, give me T in return, perfectly clear i guess? Now when you call the function with a floating point, real, double, float..., you will get what you asked for. Now what about other types? Say you call it with a non floating type, when compiler tries to divide the first thing it will encounter that one of two elements of the operation is a non-float, since we enforced a rule, it gives warning or error.
Mar 28 2010
On Sun, 28 Mar 2010 23:46:55 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Sun, 28 Mar 2010 14:29:52 -0400, so <so so.do> wrote:I don't think a language/compiler should make premature decisions when an ambiguity happens, What is warning or error mechanism for then? In your case, we have a rule at hand, and you broke it. That should require an explicit cast, Also, when you have a framework, you would have the T version of the "foo" right? I guess i am missing something here.What you are asking for is a template instantiation that depends on instantiating itself. How about a function like this? void foo(int x); T inv(T)(T m) { foo(m); return 1.0/m; } How do you know what type to use for T? It's simple when you make inv a one-liner, there is only one thing to look at. But as you start making the function more complex, then it's impossible to tell what the user actually wants. In this instance, T must be implicitly convertable to int, but also must be a floating point type. Clearly there is an error here, but where is it? This is called ambiguity, and to avoid it, the compiler makes a decision, right or wrong, based on the literal used to call the function. It expects you, the user, to help out when it doesn't make the right one. I don't think it's too much to ask. It's simply a tradeoff between being an all-powerful oracle-like compiler and being a simple-to-write compiler.What you want is implicit function template instantiation based on the return type. D doesn't do that, it doesn't even allow overloading based on the return type. However, you can infer the return type using auto: auto inv(T)(T m) { return 1.0/m; } -SteveHello! I guess, i am unable to express myself. In code : T inv(T)(T m) { return 1.0/m; } If we forget the rules of default literals that C derived languages have, just for a second. And enforce our own little rule. - no implicit casts With this in mind this code says; i gave you T, give me T in return, perfectly clear i guess? Now when you call the function with a floating point, real, double, float..., you will get what you asked for. Now what about other types? Say you call it with a non floating type, when compiler tries to divide the first thing it will encounter that one of two elements of the operation is a non-float, since we enforced a rule, it gives warning or error.What the compiler sees when deciding to instantiate is this: T inv(T)(T m) {...} And it makes a decision.I am perfectly fine with that.If you have a problem with writing inv(5.0) instead of inv(5), then maybe D just isn't for you. -SteveI am not sure what you mean really? You mean the other way around? i want : inv(5.0f), inv(5.0d), inv(5.0L) or T x; inv(x); // where T is floating point type. Thanks. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On Sun, 28 Mar 2010 15:09:35 -0400, so <so so.do> wrote:On Sun, 28 Mar 2010 23:46:55 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:It has to make a decision on literals, or else you can't use them without casting. I'd hate to write code for a compiler that requires you to cast every literal.What you are asking for is a template instantiation that depends on instantiating itself. How about a function like this? void foo(int x); T inv(T)(T m) { foo(m); return 1.0/m; } How do you know what type to use for T? It's simple when you make inv a one-liner, there is only one thing to look at. But as you start making the function more complex, then it's impossible to tell what the user actually wants. In this instance, T must be implicitly convertable to int, but also must be a floating point type. Clearly there is an error here, but where is it? This is called ambiguity, and to avoid it, the compiler makes a decision, right or wrong, based on the literal used to call the function. It expects you, the user, to help out when it doesn't make the right one. I don't think it's too much to ask. It's simply a tradeoff between being an all-powerful oracle-like compiler and being a simple-to-write compiler.I don't think a language/compiler should make premature decisions when an ambiguity happens, What is warning or error mechanism for then?In your case, we have a rule at hand, and you broke it. That should require an explicit cast, Also, when you have a framework, you would have the T version of the "foo" right? I guess i am missing something here.What you are missing is it's easy to look at a simple example and conclude that a compiler should have enough intelligence to understand what you meant in that simple example. However, you must also look at more complex cases and figure out if the rule holds for those as well. I think in your simple one-liner, it is obvious to a person that inv only compiles for floating point types. However, you want it to work for the literal "5", right? So you want the compiler to use the code of the function to deduce what the type of 5 is, knowing that the function should compile for floating point types. It just isn't a workable general solution. Code can be very complex, and to require the compiler to understand the semantic meaning of the code in this way is not how the D compiler is built. It is *told* how to compile something, and then checks that what you told it to do makes sense. It doesn't figure stuff out for itself in anything bigger than a single statement. D is supposed to be a context-free grammar.I am confused. I thought this was your problem? That it wasn't taking the body of the function into account when deciding the type of T?What the compiler sees when deciding to instantiate is this: T inv(T)(T m) {...} And it makes a decision.I am perfectly fine with that.This works today, no (except for the d is redundant)? I guess I don't really understand what you are looking for... -SteveIf you have a problem with writing inv(5.0) instead of inv(5), then maybe D just isn't for you. -SteveI am not sure what you mean really? You mean the other way around? i want : inv(5.0f), inv(5.0d), inv(5.0L) or T x; inv(x); // where T is floating point type.
Mar 29 2010
charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit On 29-mar-10, at 12:57, Steven Schveighoffer wrote:On Sun, 28 Mar 2010 15:09:35 -0400, so <so so.do> wrote:I guess I am not alone then :)On Sun, 28 Mar 2010 23:46:55 +0400, Steven Schveighoffer <schveiguy yahoo.comThis works today, no (except for the d is redundant)? I guess I don't really understand what you are looking for...wrote:[...] I am not sure what you mean really? You mean the other way around? i want : inv(5.0f), inv(5.0d), inv(5.0L) or T x; inv(x); // where T is floating point type.
Mar 29 2010
This works today, no (except for the d is redundant)? I guess I don't really understand what you are looking for... -SteveCould you please write the equivalent D code for generic inv function? I guess it would be T inv(T)(T m) { return 1 / m; } Right? With a glance, It is perfectly what i want! Now lets apply C derived language (D is one of them as we all know) rules here and analyze what is happening. Q - what is "1" ? A - "1" is an "int", which means, "signed int", also in D it is "32 bit signed it", in C bit count is implementation defined, of course D way much better. Q - what happens when i call inv(5.0f) A - "return float(1) / 5.0f" Anything wrong with questions and answers here? What i am asking is why it have to be this way. In "return 1 / float", why 1 is assumed as an integer, and consequently casted to float. In math [real numbers] > [integers] > [natural numbers}, why 1 is an integer? and especially why 1 is an 32 bit integer? T foo(T)(T k) { return k + 3; } General answer will be like, above code should fricking work, without my explicit cast! And you are right, That is perfectly fine with me! :) I again ask, for this code to work, Is it necessary "3" be a 32bit integer, or a native type at all? -- You are right, inv is a dumb function, we need a real world example. Say we have a function with 2 overloads, which might be the reasons of precision, performance... float foo(float m) {} double foo(double m) {} Now we need to call this within a generic code. void test(T)(T m) { return m * foo(0.3); } Since 0.3 is a double, double version will be called, so we should use foo(cast(T)0.3), right? When the function foo is a popular one, what am i going to do? anything other than casting at each occurrence? with functions like foo, code becomes like... void test2(T)(T m) { T n = foo1(cast(T)0.3) / foo2(cast(T)9); .... ... } And everyone thinks that he is writing generic code... Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 29 2010
On Mon, 29 Mar 2010 09:20:56 -0400, so <so so.do> wrote:You are right, inv is a dumb function, we need a real world example. Say we have a function with 2 overloads, which might be the reasons of precision, performance... float foo(float m) {} double foo(double m) {} Now we need to call this within a generic code. void test(T)(T m) { return m * foo(0.3); } Since 0.3 is a double, double version will be called, so we should use foo(cast(T)0.3), right? When the function foo is a popular one, what am i going to do? anything other than casting at each occurrence? with functions like foo, code becomes like... void test2(T)(T m) { T n = foo1(cast(T)0.3) / foo2(cast(T)9); .... ... }OK, I see the issue now. The syntax for declaring that a literal is the type of T is too verbose. This is different than what I thought you wanted. I agree this isn't the best situation. It's good that it is possible, but we should strive to find a better way. Sorry for the noise from misunderstanding. As for the better way, one possibility is using C++-style value type constructors: float(0.3) This provides a way to have T be a user-defined type as well (define static opCall or a constructor) So the test function would look like this: void test(T)(T m) { { return m * foo(T(0.3)); } It would be nice to say "in this function, assume numeric literals are of type T," but that might be too specific a solution (could only apply to builtin types). I don't think it's feasible for the compiler to infer what type it should use. -Steve
Mar 29 2010
It would be nice to say "in this function, assume numeric literals are of type T," but that might be too specific a solution (could only apply to builtin types). I don't think it's feasible for the compiler to infer what type it should use. -SteveIt would be nice indeed! My proposal"ish" idea was exactly for this problem, that removing "default literal" rule, and treating every implicit constant (constant without literal) as a generic type. I don't think it will ever happen even if i was able to provide full parsing framework, since C is a strong opponent :) Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 29 2010
What i am asking is why it have to be this way. In "return 1 / float", why 1 is assumed as an integer, and consequently casted to float. In math [real numbers] > [integers] > [natural numbers}, why 1 is an integer? and especially why 1 is an 32 bit integer? T foo(T)(T k) { return k + 3; } General answer will be like, above code should fricking work, without my explicit cast! And you are right, That is perfectly fine with me! :) I again ask, for this code to work, Is it necessary "3" be a 32bit integer, or a native type at all?well as you said in mathematics a Natural number is also an Integer which is also a Rational which is also a Real. One could say that you have an injection, an implicit cast from Natural to Integer to Rational to Real. By the way maybe you fear that the implicit cast is done at runtime, or has some hidden cost, but that is not the case, for literals it is done at compile time. In reality (and also in mathematics if you use cyclic groups, or approximate numbers) the situation becomes a lot more murky, but in the end not much changes. On 29-mar-10, at 15:47, so wrote:The example you give cannot be solved easily and efficiently (find the type to use in a function) without some kind of inference based on the return type, annotations, or Hindley Milner style type inference. annotation don't scale, using inference based on the return type is very difficult and not doable in general, few languages do it (aldor for example did it), Hindley Milner is incompatible with C. Please note that (possibly due to my C background) I like to put some type annotations, in my (limited) experience that pays off also with ML style languages, otherwise when you have ambiguity small errors can change the called functions and give surprising results. FawziIt would be nice to say "in this function, assume numeric literals are of type T," but that might be too specific a solution (could only apply to builtin types). I don't think it's feasible for the compiler to infer what type it should use. -SteveIt would be nice indeed! My proposal"ish" idea was exactly for this problem, that removing "default literal" rule, and treating every implicit constant (constant without literal) as a generic type. I don't think it will ever happen even if i was able to provide full parsing framework, since C is a strong opponent :)
Mar 29 2010
The example you give cannot be solved easily and efficiently (find the type to use in a function) without some kind of inference based on the return type, annotations, or Hindley Milner style type inference. annotation don't scale, using inference based on the return type is very difficult and not doable in general, few languages do it (aldor for example did it), Hindley Milner is incompatible with C. Please note that (possibly due to my C background) I like to put some type annotations, in my (limited) experience that pays off also with ML style languages, otherwise when you have ambiguity small errors can change the called functions and give surprising results. FawziFinally i am able to explain it with 2 words, Hindley Milner :) I want credit too! i also found it independently! Thanks for the explanation, i don't really like non-system, non-generic languages, non-D like languages. Especially when a language has dumb reasons for not providing an utility. (Java operator overloading case) D is the best choice for me by miles and i can learn to live with casts as i did in C++. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 29 2010
On 29-mar-10, at 16:57, so wrote:ehm actually Hindley Milner is not enough for what you requested, it can find types of functions, but integers are still separated from floats. It can't cope well with incompatible overloads or conversions (they have type a->b)... what you want is really return type based inference something that is hard, as said as far as I know only aldor did thatThe example you give cannot be solved easily and efficiently (find the type to use in a function) without some kind of inference based on the return type, annotations, or Hindley Milner style type inference. annotation don't scale, using inference based on the return type is very difficult and not doable in general, few languages do it (aldor for example did it), Hindley Milner is incompatible with C. Please note that (possibly due to my C background) I like to put some type annotations, in my (limited) experience that pays off also with ML style languages, otherwise when you have ambiguity small errors can change the called functions and give surprising results. FawziFinally i am able to explain it with 2 words, Hindley Milner :) I want credit too! i also found it independently!Thanks for the explanation, i don't really like non-system, non- generic languages, non-D like languages. Especially when a language has dumb reasons for not providing an utility. (Java operator overloading case) D is the best choice for me by miles and i can learn to live with casts as i did in C++. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 29 2010
On 28-mar-10, at 14:48, so wrote:I don't think it is that complex, if it is please point me. It is simple math. "3" the number belongs to many number systems. Making default int (actually "signed int") is the source of complexity, same goes for "0.3". For function overload case: foo(float) foo(double) foo(real) If i call the overloaded functions above with foo(0.3), since i haven't explicitly stated (in C world, i explicitly stated it is double) which function i refer, it is my fault, compiler should warn/error or give me the highest precision available, you name it.or give you the "default" precision. And note that this problem is not what you pointed out initially, but something I gave. I don't see the same problem with signed int...The reason might be compatibility but i am unable to see any efficiency there.double occupies less space and can use SSE instructions.What i want is simple, in a generic code, which in this case a template, i should be able to write the code below with "zero" implicit casts. T inv(T m)() { return 1.0 / m; } What do you see in this code?invalid code?What the user wants?probably T inv(T)(T m) { return 1 / m; }User explicitly stated that he wants "1.0" in the type of T. So when "T" is float, give the float version of "1.0".Integers are the only values that can be represented without any approximation (unless you resort to rationals, or inefficient representations that are probably ok only at compile time or in very specific applications). So generic code should use integers, not floating points. You might argue that the way to get a floating point literal of type T is ugly: cast(T)1.0 for example fortran uses 1.0_T, but one can definitely live with it, anyway normally you should use integers, generic floating point literals is not really something that is so well defined...If i am not mistaken, this is actually how constant folding actually works, see the page. Thanks. On Sun, 28 Mar 2010 17:20:41 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:no the answer is more complex: for integers normally the smallest possible integral type is used (but not exactly int wins in some occasions, check the exact rules) and then implicit conversion can take place. The rules are such that it should do what one means most times (so conversion to long or uint is ok), but there are some pitfalls, often associated to conversion to unsigned (that I find useful though, even if it can lead to bugs in some occasions, and there are some reasons to like infinite integers as some languages have). Still if you write a very large number it is a long for example. floating point numbers are a bit different (because they are always approximated), but the philosophy is similar. The absence polysemus literals is not a problem in my opinion, you can avoid that having good implicit casting rules. unexpected results normally happen just when you have something very ambiguous. For example if you have an overloaded function and you call it with a literal then in *any* language you need to decide which default value has the literal (to decide with which type to start before looking at implicit conversions). D (like C) chooses int for for 3, and double for 0.3 (the latter I suppose for C compatibility and efficiency reasons, because one could argue that real would be a "safer" choice). Yes there are some dark corners, but I don't see things that make generic programming impossible. Maybe if you would say what you try to do you would receive more meaningful answers. Fawzi-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
or give you the "default" precision. And note that this problem is not what you pointed out initially, but something I gave.That is it, whole point, what the heck is a default literal or precision in a generic code?double occupies less space and can use SSE instructions.float faster and use half of double, that is not a valid argument, and it is not a valid answer to the problem at hand. If i want double i must state it "0.5d", float "0.5f" real "0.5L", we are talking about again "generic" code. There are too many implicit casts, main reason is because there are default literals, am i wrong?invalid code? probably T inv(T)(T m) { return 1 / m; }Now you are just doing it for the sake of argument. :P This is another function, for another purpose.Integers are the only values that can be represented without any approximation (unless you resort to rationals, or inefficient representations that are probably ok only at compile time or in very specific applications). So generic code should use integers, not floating points. You might argue that the way to get a floating point literal of type T is ugly: cast(T)1.0 for example fortran uses 1.0_T, but one can definitely live with it, anyway normally you should use integers, generic floating point literals is not really something that is so well defined...This is not only about floating point types, same applies to integers. 3 is default "int" right? Imagine what happens if it wasn't. ushort m0 = 30000000000000000000000000000000000; // error ubyte m1 = 3; // no implicit cast, fine byte m2 = 3; // same short m3 = 3; // same ubyte m5 = -3; // error ushort m6 = -3; // error And for the floating point case : float m = 0.5; double n = 0.5; real r = 0.5; What is wrong with this? Thanks. Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On 28-mar-10, at 15:44, so wrote:the one to use when things are ambiguosor give you the "default" precision. And note that this problem is not what you pointed out initially, but something I gave.That is it, whole point, what the heck is a default literal or precision in a generic code?really the compiler cannot parse your function, and I can't either, to me what you meant is the code I wrote.double occupies less space and can use SSE instructions.float faster and use half of double, that is not a valid argument, and it is not a valid answer to the problem at hand. If i want double i must state it "0.5d", float "0.5f" real "0.5L", we are talking about again "generic" code. There are too many implicit casts, main reason is because there are default literals, am i wrong?invalid code? probably T inv(T)(T m) { return 1 / m; }Now you are just doing it for the sake of argument. :P This is another function, for another purpose.I really don't understand your point that is *exactly* what the compiler does...Integers are the only values that can be represented without any approximation (unless you resort to rationals, or inefficient representations that are probably ok only at compile time or in very specific applications). So generic code should use integers, not floating points. You might argue that the way to get a floating point literal of type T is ugly: cast(T)1.0 for example fortran uses 1.0_T, but one can definitely live with it, anyway normally you should use integers, generic floating point literals is not really something that is so well defined...This is not only about floating point types, same applies to integers. 3 is default "int" right? Imagine what happens if it wasn't. ushort m0 = 30000000000000000000000000000000000; // error ubyte m1 = 3; // no implicit cast, fine byte m2 = 3; // same short m3 = 3; // same ubyte m5 = -3; // error ushort m6 = -3; // errorAnd for the floating point case : float m = 0.5; double n = 0.5; real r = 0.5; What is wrong with this?nothing and the compiler accepts it... It seems to me that you don't even know the language, and you want find "problems" in it that aren't there. Your code is invalid, I gave a valid code, which I think solves the problems you are trying to illustrate, and argued about the pitfalls of "generic float literals" (no language that I know of has good support for them, and that in D you would write with cast(T)literal). In D the return type of a function (like in many other languages) is determined by its arguments, so it makes no sense to having it determined from operations in its inside, like 1.0/m, T is determined *before* the call and independently from what happens inside the function
Mar 28 2010
the one to use when things are ambiguosWhat ambiguity you are talking about? It is generic code, everything known.really the compiler cannot parse your function, and I can't either, to me what you meant is the code I wrote.So you are saying a compiler is unable to parse this : T inv(T)(T m) { return 1.0 / m; } And perfectly fine with parsing this one? T inv(T)(T m) { return 1 / m; } A coder who has the basic knowledge of "you can't take an inverse of an integer" wouldn't write the second code, and when he does, he should understand if the second code pops the error when he pass a floating point argument, inv(5.0) Why? Remember the rule again, no implicit casts.nothing and the compiler accepts it...Now you don't even read what i write, what is the point replying then, move on. :)It seems to me that you don't even know the language, and you want find "problems" in it that aren't there. Your code is invalid, I gave a valid code, which I think solves the problems you are trying to illustrate, and argued about the pitfalls of "generic float literals" (no language that I know of has good support for them, and that in D you would write with cast(T)literal). In D the return type of a function (like in many other languages) is determined by its arguments, so it makes no sense to having it determined from operations in its inside, like 1.0/m, T is determined *before* the call and independently from what happens inside the functionI am not sure if i should answer you with the attitude of yours but lets have it. T is determined before the call, did i say anything against or i was the one proposing improvement over it? :) T is determined before the call yes, when i call inv(4.0f) it will be "1.0f/4.0f", with "zero implicit casts" in your case it will be "1/4.0f" which is either implicit cast or an error/warning. Thanks. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On 28-mar-10, at 16:22, so wrote:right f(1) with overloaded function f is not ambiguous.the one to use when things are ambiguosWhat ambiguity you are talking about? It is generic code, everything known.you know with someone that uses a clearly fake email, does not bother to actually check if the compiler doesn't by chance already do what he would like to have, and the reason he bashes D, says "I don't want implicit casts, because otherwise you know what I would like to have happens, and besides cast is a nasty thing, so implicit cast must be bad or something, and the name doesn't sound good... so you have to abide my rule of no implicit cast" well that looks like a troll, so as superdan says "u don't reason with'em trollz." still sometime you have to answer them just so that outsiders realizes that those things are just FUD, and because sometime there is really someone that wants to meaningfully contribute to the discussions, but starts out in a bad way... D numerical system is not perfect, and there are possible improvements, for example I think that it could learn a couple of things from fortran 90 numerical system (which mostly could be done with templates), but it is definitely very usable. goodbye Fawzireally the compiler cannot parse your function, and I can't either, to me what you meant is the code I wrote.So you are saying a compiler is unable to parse this : T inv(T)(T m) { return 1.0 / m; } [...] I am not sure if i should answer you with the attitude of yours but lets have it.
Mar 28 2010
Just wow... On Sun, 28 Mar 2010 21:23:00 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:On 28-mar-10, at 16:22, so wrote:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/right f(1) with overloaded function f is not ambiguous.the one to use when things are ambiguosWhat ambiguity you are talking about? It is generic code, everything known.you know with someone that uses a clearly fake email, does not bother to actually check if the compiler doesn't by chance already do what he would like to have, and the reason he bashes D, says "I don't want implicit casts, because otherwise you know what I would like to have happens, and besides cast is a nasty thing, so implicit cast must be bad or something, and the name doesn't sound good... so you have to abide my rule of no implicit cast" well that looks like a troll, so as superdan says "u don't reason with'em trollz." still sometime you have to answer them just so that outsiders realizes that those things are just FUD, and because sometime there is really someone that wants to meaningfully contribute to the discussions, but starts out in a bad way... D numerical system is not perfect, and there are possible improvements, for example I think that it could learn a couple of things from fortran 90 numerical system (which mostly could be done with templates), but it is definitely very usable. goodbye Fawzireally the compiler cannot parse your function, and I can't either, to me what you meant is the code I wrote.So you are saying a compiler is unable to parse this : T inv(T)(T m) { return 1.0 / m; } [...] I am not sure if i should answer you with the attitude of yours but lets have it.
Mar 28 2010
bearophile Wrote:so:You meant "polysemous", right? :-) Cheers JustinWhy "3" is an int? Why "0.3" is a double?A possible answer: because D2 has no polysemus literals yet :-) Bye, bearophile
Mar 28 2010
What is interesting about it is, DMD already has the solution, and it is there, implemented! Just check the page : http://www.digitalmars.com/d/2.0/float.html Read the constant folding. If you already have this capabilities, why limit the user? C was a great language but lets get over with this backward-support paranoia. :) Thanks. On Sun, 28 Mar 2010 15:02:25 +0400, so <so so.do> wrote:Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks!-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
so wrote:What is interesting about it is, DMD already has the solution, and it is there, implemented! Just check the page : http://www.digitalmars.com/d/2.0/float.html Read the constant folding. If you already have this capabilities, why limit the user?It's a bit surprising how D treats numeric literals. Although (say) 2.1 is of type double, 2.1f is of type float, and 2.1L is of type real, they all have exactly the same value. (Not entirely true. Oddly, the maximum exponent value does seem to be limited. I think that's something which should change, as I don't think it makes much sense). The type only affects the type of expressions involving that value, it doesn't change the value. Range propagation isn't fully implemented in DMD2 yet. Once it's in, the situation will improve a little more. It's already much better than the situation in C or C++. But I agree that it's still not perfect.C was a great language but lets get over with this backward-support paranoia. :) Thanks. On Sun, 28 Mar 2010 15:02:25 +0400, so <so so.do> wrote:Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks!
Mar 28 2010
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! :) Thanks. On Sun, 28 Mar 2010 23:34:43 +0400, Don <nospam nospam.com> wrote:so wrote:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/What is interesting about it is, DMD already has the solution, and it is there, implemented! Just check the page : http://www.digitalmars.com/d/2.0/float.html Read the constant folding. If you already have this capabilities, why limit the user?It's a bit surprising how D treats numeric literals. Although (say) 2.1 is of type double, 2.1f is of type float, and 2.1L is of type real, they all have exactly the same value. (Not entirely true. Oddly, the maximum exponent value does seem to be limited. I think that's something which should change, as I don't think it makes much sense). The type only affects the type of expressions involving that value, it doesn't change the value. Range propagation isn't fully implemented in DMD2 yet. Once it's in, the situation will improve a little more. It's already much better than the situation in C or C++. But I agree that it's still not perfect.C was a great language but lets get over with this backward-support paranoia. :) Thanks. On Sun, 28 Mar 2010 15:02:25 +0400, so <so so.do> wrote:Hello, after a little discussion on D.learn, i better ask this here since i didn't get much replies. Two lil questions. Why "3" is an int? Why "0.3" is a double? Thanks!
Mar 28 2010
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???
Mar 28 2010
Don Wrote:so wrote:he wanna 1.0 to adapt to T. i'm sayin' if u pass float to inv 1.0 gotta be 10.F but if u pass real to in 1.0 gotta be 1.0L or shit. really dat iz happening already I guess but therez conversion shit goin' down. hey mr. so i think u should check a thread on octal literalz shit a week ago or so. like octal!"177" iz 0177 and octal!"177L" iz 0177L and shit. if needed this can be done for floating shit too. T inv(T)(T shit) { return floating_literal!(T, "1.0") / shit; } floating_literal give u da right type. prolly therez some simple string mixin n shit.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.u mean lossy not lossless homez.(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???yeah. and shit 0 its an octal constant. fuck.
Mar 28 2010
superdan Wrote:he wanna 1.0 to adapt to T. i'm sayin' if u pass float to inv 1.0 gotta be 10.F but if u pass real to in 1.0 gotta be 1.0L or shit.dats 1.0F not 10.F. shit. but im sure u peoples feel me.
Mar 28 2010
On Mon, 29 Mar 2010 00:46:20 +0400, Don <nospam nospam.com> wrote:so wrote: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/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???
Mar 28 2010
A few errors, sorry about that!- operator has a generic operand (4 * 7 / 2), expect it in the and keep parsing.which should be "expect it in the type of T and keep parsing"m is here float and operation * has a generic operandand ignore this line :) Thanks! -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Mar 28 2010
On 28-mar-10, at 22:34, so wrote:On Mon, 29 Mar 2010 00:46:20 +0400, Don <nospam nospam.com> wrote:why do you see implicit cast as bad? for me the change from 5 to 5.0f that you have above *is* an implicit cast, and is exactly what you want. For 4 * 7 / 2, well that should either be calculated as integer or as float, it is unlikely that both are correct. Some languages decided to use a different symbol for integer division and float division. without that the thing is kind of ambiguous, and D chooses integer division, and only later implicit conversion to float. What I do agree with is that writing generic float literals is cumbersome (using cast(T)x). Implicit cast is what happens to stuff that can also be seen as a type X so natural number -> integers,... implicit cast should not discard precision, and should maintain the value, and is a *good* thing in general (if the rules are sensible).so wrote: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.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???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.that gets easily very annoying, even aldor, that basically did all what you wanted, and complained about unclear overload did an exception for integers, so that they would default to Int.... Still I find D approach reasonable
Mar 28 2010
why do you see implicit cast as bad? for me the change from 5 to 5.0f that you have above *is* an implicit cast, and is exactly what you want. For 4 * 7 / 2, well that should either be calculated as integer or as float, it is unlikely that both are correct. Some languages decided to use a different symbol for integer division and float division. without that the thing is kind of ambiguous, and D chooses integer division, and only later implicit conversion to float. What I do agree with is that writing generic float literals is cumbersome (using cast(T)x).Hello! Implicit cast is bad, for performance reasons, for clarity, and you can't call it generic. With the rule i presented "5 to 5.0f" is not an implicit cast, How? It is implicit in C derived languages just because 5 is int, it has a native type, this is language constraint. In my case 5 is not a native type, and by definition 5 to 5.0f is not an implicit cast, 5 and 5.0f is the same thing! For 4 * 7 / 2, yes you are right it was an error on my side which i corrected with next reply, also i wasn't clear enough. So, i meant to say there "expect it in the type of T", and that means since the operator before them expects it in type T, Treat them as type T, if you can't, pop warning/error, so lets say T is a floating point type, compiler can do (4 * 7 / 2) operation in the highest possible precision for the constant folding purposes and return the result, which will be again a "generic floating point type".Implicit cast is what happens to stuff that can also be seen as a type X so natural number -> integers,... implicit cast should not discard precision, and should maintain the value, and is a *good* thing in general (if the rules are sensible).Perfectly fine with me when the rules are really sensible, but isn't the point of templates, being a template rather than casting? Is this a generic code then? uint add(uint m, uint n) { return m + n; } By implicit/explicit casts i can pass all the types here.If we want add(0) to just work... why it should explicitly be an "int" and not a byte or real? For me converting it to highest precision integer would be better choice, maybe it is the reason why it was "int". At the time of C there wasn't any integer longer than say int? Sorry if this sounds naive! :) Thanks. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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.that gets easily very annoying, even aldor, that basically did all what you wanted, and complained about unclear overload did an exception for integers, so that they would default to Int.... Still I find D approach reasonable
Mar 28 2010
On 28-mar-10, at 22:46, Don wrote:so wrote:ok if you have a real message, I am sorry to have been so harsh, I was a bit hard due to other trolls going on... sorry if I did not really catch your message, but next time try to actually bring an actual example of what the compiler does wrong, it will help understand your problem.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.well the correct thing to do (I thought that was what was done possibly CTFE excluded) is to always do constant folding with the maximum precision available (maybe even more than real), and only at the end convert to the type. so that one could write cast(real)0.555_555_555_555_555_555 and that is equivalent to 0.555_555_555_555_555_555L and thus basically cast(T)xxx is the generic way to write a float literal of type T. If this is not like that, then it should indeed be changed... I still argue that using integers if possible often a better choice. The language that that solved the problem of floating points, integers & co most cleanly is probably aldor (http://www.aldor.org/) but it is a dead language.(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???and maybe 1 the identity? the aldor solution is probably a bit too challenging but allowed both things... Integer were arbitrary length integrals converted to the final type with implict cast (fromInteger), floats were converted to Rationals and then to the correct type with implicit cast (fromRational). 0 and 1 could be implicitly casted separately to allow things like vectors and matrixes to use them without defining a full fromInteger cast. I find that for integers D normally does the correct thing, and for floats I thought it was closer that what it might be (i.e. arbitrary precision calculations and cast to the final type). about the isFloatingPoint one can still one can easily write add(T)(T x) if(is(T:real)) or something like that, and probably solve the problem. what would be nice is to have templates to find types with a given precision and so like one does in fortran. also i use templates to get the complex type or real type of a given type and so on. These things should probably be in the library... so with some extra templates probably these things could be solved.
Mar 28 2010
On Mon, 29 Mar 2010 01:45:09 +0400, Fawzi Mohamed <fawzi gmx.ch> wrote:ok if you have a real message, I am sorry to have been so harsh, I was a bit hard due to other trolls going on... sorry if I did not really catch your message, but next time try to actually bring an actual example of what the compiler does wrong, it will help understand your problem.D is the best language i have seen, and that is why i am here. The point i am trying to make is something you all mostly say in this newsgroup. Even it is the language choice of mine, C++ made some major mistakes by blindly copying some of the rules/syntax C has, and tried to build many things on top of them. As Walter said for the arrays not being first class citizens in C and unfortunately C++. For me this is a case exactly like arrays... For a mainly generic/system language, 0 shouldn't be an int and 0.0 should not be a double, and i am having hard time to find reasons why it is still as it is other than backwards/root compatibility. Thanks.-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/(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.well the correct thing to do (I thought that was what was done possibly CTFE excluded) is to always do constant folding with the maximum precision available (maybe even more than real), and only at the end convert to the type. so that one could write cast(real)0.555_555_555_555_555_555 and that is equivalent to 0.555_555_555_555_555_555L and thus basically cast(T)xxx is the generic way to write a float literal of type T. If this is not like that, then it should indeed be changed... I still argue that using integers if possible often a better choice. The language that that solved the problem of floating points, integers & co most cleanly is probably aldor (http://www.aldor.org/) but it is a dead language.(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???and maybe 1 the identity? the aldor solution is probably a bit too challenging but allowed both things... Integer were arbitrary length integrals converted to the final type with implict cast (fromInteger), floats were converted to Rationals and then to the correct type with implicit cast (fromRational). 0 and 1 could be implicitly casted separately to allow things like vectors and matrixes to use them without defining a full fromInteger cast. I find that for integers D normally does the correct thing, and for floats I thought it was closer that what it might be (i.e. arbitrary precision calculations and cast to the final type). about the isFloatingPoint one can still one can easily write add(T)(T x) if(is(T:real)) or something like that, and probably solve the problem. what would be nice is to have templates to find types with a given precision and so like one does in fortran. also i use templates to get the complex type or real type of a given type and so on. These things should probably be in the library... so with some extra templates probably these things could be solved.
Mar 28 2010
Don wrote:(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.It depends. The D compiler internally stores all floating point constants, regardless of type, in full 80 bit precision. Constant folding and CTFE are all carried out in 80 bit precision regardless of type. The only time it is actually truncated to the shorter formats is when writing it out to the object file. The central idea is that more precision == better. If your floating point algorithm breaks if precision increases, then the algorithm is a bad one. The only time I've seen code that relied on roundoff errors is in test suites that specifically tested for it.
Mar 28 2010
On 29-mar-10, at 00:04, Walter Bright wrote:Don wrote:ok good that is actually how I though, so that cast(T)x is indeed the way to write a generic float literal. I thought that was the case, but seeing Don implying something different I got worried that my coding was based on wrong assumptions.(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.It depends. The D compiler internally stores all floating point constants, regardless of type, in full 80 bit precision. Constant folding and CTFE are all carried out in 80 bit precision regardless of type. The only time it is actually truncated to the shorter formats is when writing it out to the object file.The central idea is that more precision == better. If your floating point algorithm breaks if precision increases, then the algorithm is a bad one.I fully agree.The only time I've seen code that relied on roundoff errors is in test suites that specifically tested for it.
Mar 28 2010
Walter Bright wrote:Don wrote:There's some oddities. //enum A = 1.0e400; // Error: number is not representable enum B = 1.0e200 * 1e200; // yes it is! enum C = 1.0e400L; static assert(B==C); So there's a bit of schizophrenia about whether the 'L' suffix changes which values are representable, or whether it is just a type marker. I think we should tighten things up a little bit, but I don't think it's a big deal.(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.It depends. The D compiler internally stores all floating point constants, regardless of type, in full 80 bit precision. Constant folding and CTFE are all carried out in 80 bit precision regardless of type. The only time it is actually truncated to the shorter formats is when writing it out to the object file. The central idea is that more precision == better. If your floating point algorithm breaks if precision increases, then the algorithm is a bad one. The only time I've seen code that relied on roundoff errors is in test suites that specifically tested for it.
Mar 29 2010
On 29-mar-10, at 10:29, Don wrote:Walter Bright wrote:good to have the numerics expert look into this. Yes I think the situation is really quite ok, for example (now having some doubts) I just checked (to be sure the correct thing would happens as I thought) and T mult1(T)(T x){ return 1.000000000000000001*x; } assert(mult1(1.0f)==1.0f,"float"); assert(mult1(1.0)==1.0,"double"); assert(mult1(1.0L)==1.0L*1.000000000000000001L,"real"); :)Don wrote:There's some oddities. //enum A = 1.0e400; // Error: number is not representable enum B = 1.0e200 * 1e200; // yes it is! enum C = 1.0e400L; static assert(B==C); So there's a bit of schizophrenia about whether the 'L' suffix changes which values are representable, or whether it is just a type marker. I think we should tighten things up a little bit, but I don't think it's a big deal.(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.It depends. The D compiler internally stores all floating point constants, regardless of type, in full 80 bit precision. Constant folding and CTFE are all carried out in 80 bit precision regardless of type. The only time it is actually truncated to the shorter formats is when writing it out to the object file. The central idea is that more precision == better. If your floating point algorithm breaks if precision increases, then the algorithm is a bad one. The only time I've seen code that relied on roundoff errors is in test suites that specifically tested for it.
Mar 29 2010