February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | Walter wrote: > Implicit narrowing conversions: > > "Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote in message > news:cvue5s$1sh4$1@digitaldaemon.com... > >>Or that floating=>integral >>narrowing is wrong in *all* cases, and integral=>integral narrowing is >>right in *all* cases. Doesn't stand up to common sense. > > > Of course it doesn't stand up to common sense, and it is not what I said. > What I did say, perhaps indirectly, is that implicit floating->integral > conversions in the wild tend to nearly always be a mistake. For the few > cases where it is legitimate, a cast can be used. But the reverse is true > for other integral conversions. They happen frequently, legitimately. Having > to insert casts for them means you'll wind up with a lot of casts in the > code. > > Having lots of casts in the code results in *less* type safety, not more. > Having language rules that encourage lots of casting is not a good idea. > Casts should be fairly rare. > > It isn't all or nothing. It's a judgement call on the balance between the > risk of bugs from a narrowing conversion and the risk of bugs from a cast > masking a totally wrong type. With integral conversions, it falls on the one > side, with floating conversions, it falls on the other. > > Warnings: > > I'm pretty familiar with warnings. If a compiler has 15 different warnings, > then it is compiling 15! (15 factorial) different languages. Warnings tend Assuming 15 different on-offable compiler warning switches, one would tend to think that it should be 2^15 different languages? Or did I miss something? > to be unique to each compiler vendor (sometimes even contradictory), making > more and more different languages that call themselves C++. Even worse, with > each warning often comes a pragma to turn it off here and there, because, > well, warnings are inherently wishy-washy and often wrong. Now I download > Bob's Cool Project off the net, and compile it. I get a handful of warnings. > What do I do about them? I don't know Bob's code, I don't know if they're > bugs or not. I just want a clean compile so I can use the program. If the > language behaves consistently, I've got a better chance of that happening. > Warnings make a language inconsistent. > > There are a lot of things Java has done wrong, and a lot they've done right. > One of the things they've done right is specify the language so it is > consistent from platform to platform. A Java program compiles successfully > or it does not, there are no warnings. If it compiles successfully and runs > correctly on one platform, chances are far better than they are for C++ that > it will compile and run correctly without modification on another platform. > You know as well as anyone how much work it is to get a complex piece of > code to run on multiple platforms with multiple C++ compilers (though this > has gotten better in recent years). > > The idea has come up before of creating a "lint" program out of the D front > end sources. It's an entirely reasonable thing to do, and I encourage anyone > who wants to to do it. It would serve as a nice tool for proving out ideas > about what should be an error and what shouldn't. > > |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | On Mon, 28 Feb 2005 02:01:18 -0800, Walter wrote: > "Walter" <newshound@digitalmars.com> wrote in message news:cvuku9$24j5$1@digitaldaemon.com... >> But the reverse is true >> for other integral conversions. They happen frequently, legitimately. > Having >> to insert casts for them means you'll wind up with a lot of casts in the code. > > An example is in order: > > byte b; > ... > b = b + 1; > > That gives an error if implicit narrowing conversions are disallowed. You'd have to write: > > b = cast(byte)(b + 1); > > or, if writing generic code: > > b = cast(typeof(b))(b + 1); Unless the '1' was interpreted to be a byte rather than an int. DMD gives up trying to soon. A '1' is a member of many integer subsets, not just the 'int' subset. -- Derek Melbourne, Australia |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek | Derek wrote: > Hmmm... I think we have a problem. I would have said that 12 is an > *integer*, but I couldn't tell you what sort of integer it is until I saw > it in context. I believe that 12 could be any of ... > > byte > ubyte > short > ushort > int > uint > long > ulong I think "smallest type that could possibly match" would be a good rule ? Thus, 42 would be a byte, 4242 a short, "hello" would be a char[] and "smörgåsbord" a wchar[] (just an idea, what do you think... ?) > All are integers, but they are all different subsets of the integer set. > And you are still absolutely positive that 12 is only an int? Could it not > have been a uint? If not, why not? Because then you say 12U, if you mean unsigned ? (just as 0.0f is a float, and 0.0 is a double...) --anders |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anders F Björklund | On Mon, 28 Feb 2005 11:35:05 +0100, Anders F Björklund wrote: > Derek wrote: > >> Hmmm... I think we have a problem. I would have said that 12 is an *integer*, but I couldn't tell you what sort of integer it is until I saw it in context. I believe that 12 could be any of ... >> >> byte >> ubyte >> short >> ushort >> int >> uint >> long >> ulong > > I think "smallest type that could possibly match" would be a good rule ? > > Thus, 42 would be a byte, 4242 a short, "hello" would be a char[] and "smörgåsbord" a wchar[] (just an idea, what do you think... ?) > >> All are integers, but they are all different subsets of the integer set. And you are still absolutely positive that 12 is only an int? Could it not have been a uint? If not, why not? > > Because then you say 12U, if you mean unsigned ? > (just as 0.0f is a float, and 0.0 is a double...) > > --anders So maybe all integer subsets need a literal decorator. How whould I indicate the 42 is meant to be a ushort? -- Derek Melbourne, Australia |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kris | Kris wrote: > There are serious issues here. Pretending it's all OK doesn't > make them go away, and it would be far more productive if you > were at least open to thinking about how the whole mess could > be resolved cleanly and elegantly. I am not trying to cut your > limbs off! :-) Maybe we should do it ourselves? Discuss it here, and if/when we come to a resolution, then ask Walter to reconsider? My point being that Walter gets quite a few demands to think about a number of things, all while he's also writing DMD, running a company, having a family, etc. Maybe we could start with experimenting the idea that if D had no implicit casts at all. Then what would happen. (This is not offensive, it's just that in my experience one should investigate the perimeter and then approach the center.) With the combined practical and theoretical knowledge on this forum, we may very well come up with something worthwhile. |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter |
Walter wrote:
> An example is in order:
>
> byte b;
> ...
> b = b + 1;
>
> That gives an error if implicit narrowing conversions are disallowed. You'd
> have to write:
>
> b = cast(byte)(b + 1);
>
> or, if writing generic code:
>
> b = cast(typeof(b))(b + 1);
>
> Yuk.
I assume this is because of Natural number literals being integers? Now, there's a gratuituous widening implicit cast -- which then results to the narrowing cast later, right?
I'd wish such literals get implicitly cast to the type "needed".
Or better yet, cast to the smallest possible type.
|
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek | Derek wrote: >>Thus, 42 would be a byte, 4242 a short, "hello" would be a char[] >>and "smörgåsbord" a wchar[] (just an idea, what do you think... ?) Let's leave the strings out of this, by the way, since it might as well use char[] always (works fine for both) Got myself confused with 'a' => char, 'å' => wchar, which was what I meant to write in the first place ;-) > So maybe all integer subsets need a literal decorator. How whould I > indicate the 42 is meant to be a ushort? "cast(ushort) 42U" :-) In theory the part-register int types; byte and short, *could* have suffixes too. But casts work in practice ? Can't say I have worried about the type of int literals much, they have always been "int" (but that was since C) And as long as "true" is of the type bit in D, I haven't really started to worry about the other D types either ? The only one with a designated type in D at the moment is long, which has the L suffix appended - as in 42L... For the floating point types, all three have suffixes. Even if the extended/real type might just be double too. (D only *guarantees* 64 bits of precision for "real", but provides 80 bits on X86 hardware. Other CPUs vary) --anders |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | >> But the reverse is true
>> for other integral conversions. They happen frequently, legitimately.
>Having
>> to insert casts for them means you'll wind up with a lot of casts in the code.
>
>An example is in order:
>
> byte b;
> ...
> b = b + 1;
>
>That gives an error if implicit narrowing conversions are disallowed. You'd have to write:
>
> b = cast(byte)(b + 1);
>
>or, if writing generic code:
>
> b = cast(typeof(b))(b + 1);
>
>Yuk.
>
The type of string literals is infered by the context. Couldn't this be done with integer lietrals, too? If byte + byte results in byte the above wouldn't be a problem.
-- Matthias Becker
|
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | "Walter" <newshound@digitalmars.com> wrote in message news:cvuku9$24j5$1@digitaldaemon.com... > > Implicit narrowing conversions: > > "Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote in message news:cvue5s$1sh4$1@digitaldaemon.com... >> Or that floating=>integral >> narrowing is wrong in *all* cases, and integral=>integral narrowing >> is >> right in *all* cases. Doesn't stand up to common sense. > > Of course it doesn't stand up to common sense, and it is not what I said. Maybe I misspoke. When I said "You're telling us ... that floating=>integral narrowing is wrong in *all* cases, and integral=>integral narrowing is right in *all* cases." I didn't mean that you've explicitly said that. Rather it is implicit in the fact that there are no warnings / compiler switches / pragmas / whatever. A fixed decision has been made, which the D programmer has precisely no power to adjust. Now, in a general sense that's right and proper. People cannot and should not be able to change the language willy-nilly. But the fine print on this issue is that you've allowed any implicit integral=>integral conversion, and disallowed any floating point=>integral conversion. That's what I'm objecting to. It's an all or nothing judgment, in a case - int=>int conv - that's not all or nothing: int=>long is ok in general, int=>bool is not ok in general. I cannot see the sense in the argument that says those two things should be treated alike. > What I did say, perhaps indirectly, is that implicit > floating->integral > conversions in the wild tend to nearly always be a mistake. For the > few > cases where it is legitimate, a cast can be used. But the reverse is > true > for other integral conversions. They happen frequently, legitimately. > Having > to insert casts for them means you'll wind up with a lot of casts in > the > code. > > Having lots of casts in the code results in *less* type safety, not more. Says who? > Having language rules that encourage lots of casting is not a good > idea. > Casts should be fairly rare. I absolutely agree. When I'm coding in C++ - and let's be honest: I do a *lot* of that - I absolutely want to know when I'm converting from a larger to a smaller int. Every single time. No exceptions. And I am *very glad indeed* that my code contains an ugly cast in it. When I, or someone else, reads m_size = static_cast<size_t>(std::distance(first, last)); it is clear that the ptrdiff_t (signed) returned by std::distance() must be explicitly converted to an unsigned type. After all, I don't want to define m_size as a signed quantity, because there's no way that a container with a -ve size makes sense. That's what happens in Java. And std::distance() cannot return size_t, because it can obviously be passed a pair of pointers, as well as iterators. There's only one place where the decision makes sense, and it only makes sense for that decision to be explicit. In the previous lines of code to that shown, we will have established that !(last < front), explicitly. And only then can we, the designers of that code, know that it's valid to convert from a signed value to an unsigned one. > It isn't all or nothing. Indeed > It's a judgement call on the balance between the > risk of bugs from a narrowing conversion Risk implies the possibility of not having them. Since I frequently am prevented from introducing bugs by judicious use of promoted compiler warnings in C++, I believe I can authoritatively stipulate that having unguarded narrowing conversions is a guaranteed source of bugs. Please point out the logical flaw in that conclusion. > and the risk of bugs from a cast > masking a totally wrong type. Please explain how this might be so. One thing that occurs: if D's cast()s are to coarse a tool, then why don't we consider the divide and conquer approach. What's wrong with a long l = -12345678901234; ubyte u = narrow(l); ??? narrow() can't be used for downcasting, or for casting between pointer types, etc. etc. This is what C++ does, albeit on an overly coarse degree. There are only static_cast reinterpret_cast const_cast dynamic_cast The good thing about C++ is that, by using templates + default paramters, one can implement custom casts. As you know, I've written several, including: union_cast - for when you have to be *really* dirty in casting interface_cast - for casting between COM interface pointers explicit_cast - for providing explicit, rather than implicit, conversion operators literal_cast - check the size of literals ptr_cast - throws bad_cast for ptrs as well as for refs I've yet to hear a single sensible criticism of a rich cast taxonomy. People say they're ugly. Well, duh! Show me how that's not a good thing People say there are too many casts. Well, that's the whole bloody point. C's uber cast sucks hard. C++'s four casts was a good start, and the facility for introducing more is a very powerful feature. Why can't we have a fine-grained approach in D? It is supposed to be an evolution > With integral conversions, it falls on the one > side, with floating conversions, it falls on the other. > > Warnings: > > I'm pretty familiar with warnings. If a compiler has 15 different > warnings, > then it is compiling 15! (15 factorial) different languages. Maybe so in theory. In practice, what competent C++ developer does not set warnings to max, allowing exceptions on a case-by-case basis? > Warnings tend > to be unique to each compiler vendor (sometimes even contradictory), > making > more and more different languages that call themselves C++. True. But I'd rather have to deal with 29 dithering but insightful geniuses than one cock-sure dogmatist. Kind of like the current schism in the 'civilised' world, no? > Even worse, with > each warning often comes a pragma to turn it off here and there, > because, > well, warnings are inherently wishy-washy and often wrong. Now I > download > Bob's Cool Project off the net, and compile it. I get a handful of > warnings. > What do I do about them? I don't know Bob's code, I don't know if > they're > bugs or not. I just want a clean compile so I can use the program. If > the > language behaves consistently, I've got a better chance of that > happening. > Warnings make a language inconsistent. That's a compelling example, and would be persuasive if you were promoting Java, where they've largely gone to town on strictness. But it just doesn't hold for a language where long l = -12345678901234; short s = l; byte b = l; is valid code. Given this, you cannot *ever* know that any code you interface to is valid. Hmm, maybe the answer is to never download any D code? > There are a lot of things Java has done wrong, and a lot they've done > right. > One of the things they've done right is specify the language so it is > consistent from platform to platform. Agreed > A Java program compiles successfully > or it does not, there are no warnings. Great. They have the luxury of being super strict. Some here would go for super strict for D. Some others - like me - would live with super strict if there's to be no variability But what we have at the moment is super slack. Given that, the analogy with Java makes no sense. > If it compiles successfully and runs > correctly on one platform, chances are far better than they are for > C++ that > it will compile and run correctly without modification on another > platform. True. But that doesn't hold for D, since we've already established that D is by definition more open to bugs that it need be. > You know as well as anyone how much work it is to get a complex piece > of > code to run on multiple platforms with multiple C++ compilers (though > this > has gotten better in recent years). I know all too well. But my experience with C++ does not incline me towards D's smaller degree of platform variability. Quite the opposite. When deciding on a language, one needs to consider a host of factors, including support over multiple platforms, efficiency, expressiveness, etc. etc. If I don't care about performance, but I do care about portability, I'm going to use Ruby. Hands down. (Except when I need a rich set of established libraries, in which case it's Python.) Since Ruby and Python are untyped, the issue of compile time control of conversions is moot. If I care about performance, I'm choosing C/C++ every time, no matter how much pain I have to go through porting between platforms. Since C++ is an almost perfect superset of C, it's easy peasy to deal with platform APIs. If I'm doing something that involves working with large teams of, how to say, junior programmers, then I'm going to use Java. I can barely think of a single reason to use .NET. The only time I've done so in a commercial context was because it could interface to a C++ library of mine with minimal effort. (The extension was <60 mins to write.) Ah, hang on, the only other time was when I needed to quickly write a non-trivial TCP test driver - the only thing I'm so far impressed about .NET is that it's got some nice networking libs. So where will D fit it? It's not untyped, so not going to be a competitor for scripting languages. So it has to compete with mindshare with Java/.NET or C/C++. To be incredibly simplistic, the problems with Java/.NET are that they treat the programmer like an idiot and are slow. The problems with C/C++ are that they are minefields for even the very experienced, and C++ is evolving into an almost impossible to understand pursuit of the intellectually pretentious. D has to be ~ as efficient as C/C++, as powerfully expressive as C++, as easy to use as Java/.NET, and have a tendency to suppress the dialectical nature of the D language at large in the line of Java/Python, rather than C++/Perl/(and to some degree Ruby), be as productive as .NET/Python. It also has to have better libs than C++ (not hard!), be easier on the end user than Java/.NET (not hard!), be easier to learn than C++/Perl/.NET (not hard!). Finally, it needs to help users avoid making errors, without nannying them and without _overly_ impinging on productivity. Now I believe that D has the potential to do all of that. At such time, it'd probably take a significant share of my development language time - which is now pretty much 80% C/C++, 20% Ruby - maybe up to 40-50%! That's why I'm sticking around. But it is _not_ there yet, and there's going to have to be a lot more argy bargy before it gets there. If it keeps the problems it has now, I _could_ still use it successfully, because I'm very experienced in C++, and am very skilled at avoiding errors in C/C++. But I wouldn't do so because I don't think it'd succeed, and I think I'd be wasting my investment of time/skills - my ambition is not to be an exponent of the next Sather/Dylan/Modula-2/whatever. And I could not recommend D as it stands now, to my clients, or to people who want to learn programming, because it holds traps for people who've not already learned hard lessons and good instincts. But I'm going to shut up now, because I _do_ believe it will come right, and that we'll end up with a pretty fine balance of all the must-haves mentioned above. You and I've already agreed that as we go through the research for DPD that we'll look in detail at all the areas, and I will provide cogent evidentiary rationale for my criticisms, rather than (actually, in addition to) my ng rants. Optimistically The Dr ..... |
February 28, 2005 Re: Method resolution sucks | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthias Becker | Matthias Becker wrote:
> The type of string literals is infered by the context. Couldn't this be done
> with integer lietrals, too? If byte + byte results in byte the above wouldn't be
> a problem.
Converting string literals is not narrowing, it's round-trip...
Besides, you still have to cast strings used as parameters if
both char[] and wchar[] method overloads have been provided ?
--anders
|
Copyright © 1999-2021 by the D Language Foundation