July 23, 2009
Walter Bright wrote:

>> Aren't immutable and enum the same thing? At least to the programmer?
> 
> Not at all. How would you declare a type that is "pointer to immutable int" using an enum? Anyhow, there was a looong thread about this a year back or so.

Then perhaps you can get rid of enum and have only immutable. Well, I'm sure you have valid reasons to keep it (like actual enumeration). But it would just seem worthwhile to try to unify them.

> Contracts didn't hit paydirt, and so haven't gotten a lot of follow-on attention.

This is too bad. It was one of the features that I liked most about D when I first started using it.

> and I never heard of ranking functions.

Yeah, they're called something different everywhere. I've seen them called loop variants or binding functions. It's the expression that strictly decreases each iteration and always remains non-negative. The existence of such an expression proves the eventual termination of the loop.

>> * No control over their use by class designer: ANY member function with one or zero parameters may be called using 'property syntax'. This is not a good thing.
> 
> Why not? Seriously, what is the semantic difference?

There are many reasons. Some have been floating around this newsgroup this very day.

* A reference to a function should mean exactly that: a reference to the function, for use in functional programming. Instead, just the name of a function now invokes a call.

* In D, &foo returns a function-pointer, but that means that D is context sensitive, since its subexpression foo would return a property value. It is confusing.

* What does D do if you have a property (p) that returns a delegate? Will
the call p() return the delegate? Or will it call the delegate?

* writefln = 5; This should just *not* be valid code. But it is.

* Real Properties have many advantages over what looks like D's ad-hoc solution. They automatically document themselves as properties both to the programmer and to IDE's (see some other posts from today). The programmer may use them to overload certain operators and mutator functions that would speed up the program. Months ago there was a big thread about Real Properties. I myself offered a suggestion for their design. I don't remember if you ever responded.

That's just a few reasons right there. D's properties lack elegance and they lack potential.

>> * No global properties: If I'm not mistaken, global functions can't be properties.
> 
> int foo() { return 3; }
> void main() { int x = foo; }
> works.

Aha. Then you may want to fix the documentation.

http://d.puremagic.com/issues/show_bug.cgi?id=3204

>>>> * Operator overloading (no fine control over comparison operators,
>>>  > fixed commutativity,
>>>
>>> This is deliberate. Operator overloading should be restricted to implementing arithmetic like operations on objects, not completely different things like what iostreams, Spirit and Boost::regex do.
>> 
>> Arithmetic like operations like matrix multiplication (which is not
>> commutative)?
> 
> I believe this is completely controllable with D.

Not if commutativity of the * operator is fixed. The documentation states that * is commutative, which in fact for integers it is. So if I overload * for matrices, for all the guarantees the docs give me, a D compiler might choose to swap the operands around (perhaps to get some memory alignment advantage), and the returned matrix would be incorrect.

>> Perhaps you misunderstand. I was referring to the algorithm that first checks for a complete match, then tries the 'reverse overload', then tries the commutative call.
> 
> I did understand it. The alternative is Koenig Lookup, and the reason for its existence. Reverse operator overloading is a bit awkward, but the awkwardness is restricted to the class in which it appears. ADL (Koenig Lookup) spreads awkwardness everywhere.

Well, I suggest that there be NO reverse overloads, that an overload should be possible in the global scope with the class giving it access to its private members (C++ uses 'friend', but there must be more elegant ways), lifting the 'this' restriction that prompted reverse overloads.

I don't know exactly what Koenig Lookup is, but from what I read on Wikipedia, it involves arbitrary access to other namespaces, which seems unnecessary. Otherwise it sounds like regular function overloading based on its parameter types, which D supports, of course.

Though I haven't read it through in detail.

>>> For && and ||, they are "short circuit" operators, and how that would sensibly interact with operator overloading I have no idea.
>> 
>> See my comments above about lazy parameter evaluation. I suggest that those operators are defined with a lazy second parameter for bools, and programmers should be allowed to overload them for other types as they please.
>> 
>>> I know of no language that allows overloading && and ||.
>> 
>> C++ does. ! too.
> 
> Oops, you're right. Here's an old thread about it: http://www.digitalmars.com/d/archives/digitalmars/D/18153.html
> 
> I can't recall ever seeing anyone use it, though. Until there's a compelling use case for it, not just it being a nice idea, I'll stick with my belief it's a bad idea.

I don't know a compelling use-case either. But that doesn't mean there isn't any. Nor are there any real dangers. Arbitrarily restricting the possibilities of D doesn't seem like the right way to go.

>> You cannot get a dedicated syntax with library support.
> 
> Of course that's true, but why is a dedicated syntax better than Tuple!(
> ...) ?

See my link just below. If tuples are available in the core language just like that, people will feel much more comfortable using them in any situation.

>> I've mentioned I'm working on a programming language myself. I haven't mentioned its name here, because I didn't think it'd be appropriate. But with your permission I can post a link to a page describing my tuples.
> 
> Sure.

http://code.google.com/p/mist/wiki/Tuples

> You can use static asserts to, at compile time, check the result of any computation, including function calls, that the compiler is able to execute at compile time. It sounds perfectly usable as unit tests to me, and in fact I do use static assert that way.

Can you allocate stuff on the heap? If not, you can't do proper unit testing at compile-time.

Perhaps I should have said that the unit-tests should be run automatically just after compilation and they should not be part of the program executable. They don't actually need to run 'at compile-time'.

>> Yes, but 'pretty clear' does not a spec make. I refer you to our earlier divide/modulo discussion.
> 
> We're going to fix the modulo thing. But the C++ standard leaves it implementation defined. How is that better?

It's not. And you understand that the modulo thing is only a symptom, right? I've found another mistake by accident just today. See the issue report I filed.

> Sure, the D spec has gaps in it. But the C++ standard also has large gaps of uselessness in it.

I agree. But at least you can count on C++ to do as specified. Where it doesn't give any guarantees, it specifies that also. With D it's mostly guesswork and experimentation.

-- 
Michiel Helvensteijn

July 23, 2009
Andrei Alexandrescu wrote:
> Rainer Deyke wrote:
>> 1. C++'s object model, complete with polymorphic value types,
> 
> What designs make good use of polymorphic value types?

In a way, that's a loaded question, since C++ classes don't stay polymorphic when passed around by value.  Actual polymorphic value types that stay polymorphic when copied would be much more useful.  However, even the limited polymorphic value types of C++ are useful.

Let's see:

  - Implementation inheritance of value types, even without actual
polymorphism, is useful.  See, for example, the curiously recurring
template pattern (and all of its uses).

    And, yes, you can achieve similar results in D by using template
mixins, but this is a specialized mechanism where C++ manages to do with
the same generalized mechanism used for polymorphism and interface
inheritance.

    I use inheritance of value types all the time.

  - Polymorphic references to value types are often useful.  D has
references to value types (in the form of 'ref' parameters and pointers)
but these are not polymorphic.  As an example, I would name the standard
C++ iostream.

    They're value types (non-copyable for the most part, but stored
directly instead of as pointers, with RAII), but they're often passed
around as polymorphic references.

    I use polymorphic references to value types occasionally.

  - C++ makes a clear distinction between a reference and the thing
being referenced.  Even if value types and polymorphism were mutually
exclusive, this distinction would be useful.  All types are consistently
treated as value types, even those types that reference another object.

  I *like* having to write 'gc_ptr<Object> p;' instead of 'Object p;'.
I *like* having to write 'p->f();' instead of 'p.f();'.  It keeps my
code clearly and more explicit.

  - C++ does not have separate rules for value types and reference
types.  All types are implicitly value types; values of all types can be
placed on the heap.  This simplifies the language by having just one set
of rules instead of separate rules for classes and structs.  Again, this
unification would be useful even if it was an error to declare a
variable of a polymorphic type as a direct variable.

>> deterministic destructors,  arbitrary copy constructors, and optional lack of default constructor.
> 
> Struct have that except for default constructor. In D, currently default constructors cannot execute code. This is a limitation that we might need to address, although it has some advantages.

There are things that copy constructors can do that the post-blit operator can't do.  Also, unless I am mistaken, D can move value types around in memory at will, which also invalidates designs that are useful in C++.

> How does the class/struct split? I think it's an enormous source of confusion for C++. C++ lore clarifies that you must decide in day one whether a class is meant to be polymorphic or monomorphic. Unfortunately that can't be expressed in the language, hence the weird cases with deriving from std::vector or getting polymorphic values unceremoniously sliced. Avoiding such mistakes are important things that C++ users must learn because there's nothing in the language stopping them from doing such nonsensical things; D very elegantly breaks that pattern by defining the language to only allow meaningful constructs.

On the contrary, the default in C++ is that a class can be used both as a value type and through a pointer as a reference type.  Even in D, value types can be turned into value types

Yes, when you copy class instances, it might be a bad idea to use the class as a base class.  And conversely, if you use the class as a base class, it might be a bad idea to pass around instances of the class by value.  It would be easy to forbid both of these at the language level, and almost as easy to fix them by creating non-slicing polymorphic value types.  But the class/struct split in D goes much deeper than that.


-- 
Rainer Deyke - rainerd@eldwood.com
July 23, 2009
Bill Baxter wrote:

> On Thu, Jul 23, 2009 at 12:09 PM, Lutger<lutger.blijdestijn@gmail.com> wrote:
>> Andrei Alexandrescu wrote:
>>
>>> Lutger wrote:
>>>> Jarrett Billingsley wrote:
>>>>
>>>>> On Thu, Jul 23, 2009 at 1:59 PM, Walter Bright<newshound1@digitalmars.com> wrote:
>>>>>> Michel Fortin wrote:
>>>>>>> If I'm not mistaken, both your D1 and D2 installer install at the same location and they will overwrite each other. I'd much prefer if D2 and D1 could coexist without having to go with a special installer or custom installation instructions. Otherwise it'll be hard for me to offer the choice between D1 and D2 in Xcode (and I certainly do want that choice to be available).
>>>>>>>
>>>>>>> Thoughts?
>>>>>> I've been switching the directories to {dmd, dmd2} so they can coexist.
>>>>> Will you rename the DMD2 compiler to 'dmd2' as well?
>>>>
>>>> That would be very convenient, please consider this.
>>>>
>>>
>>> I think moving forward D2 will be the norm, so I suggest going with dmd1 and dmd dir names and dmd1 and dmd binary names.
>>>
>>>
>>> Andrei
>>
>> Also fine, as long as they are different to ease more complex setups, plus it will make it much more convenient to create linux packages for this.
> 
> Shouldn't the strategy taken be something more akin to what multi-version packages like python and perl already do? They don't just automatically rename old python to be python<OldVersion> after every new version comes out.
> 
> On windows they call it python.exe but put it in a different directory.
> 
> On versions of linux I think there are some fancy schemes for setting up symlinks to particular versions to be the default.  Can't recall what that system was called.  "Defaults" or something like it. Anyway, seems like on linux dmd should work with that rather than just going and changing the names of exes according to whim.
> 
> --bb

Yes, I admit this is the preferred and in the end only sane way of doing it. (i have set it up like this come to think of it, don't know why). For people for which there is no default because they do work with both it is less nice though, imho.

July 23, 2009
Walter Bright wrote:
> Jarrett Billingsley wrote:
>> This "D" programming language is great because it obviates make.
> 
> 
> Ok, now about make's ability to switch compilers without having to edit config files?

So that's the killer feature of make? I don't know about you, but I always use only one D compiler. It's in $PATH, and the actual binary can be I-don't-know-where.

Now nobody is saying that dsss/rebuild/bud/xfbuild eliminate _all_ uses of make. But for a typical D project, writing makefiles is pure bloat and a waste of time.
July 23, 2009
Eldar Insafutdinov wrote:

> Ary Borenszweig Wrote:
...
>> For instance properties seem to be a fundamental thing in Delphi and C#. When you are debugging and you watch some varaible, the debugger automatically allows you to expand a node and see the varaible's properties. You can't do that with D because any function that has zero parameters could be a property, even though some functions aren't properties.
> 
> While working on QtD I have also come up with the conclusion that D needs proper properties. Qt itself greatly relies on properties and it makes a lot of cool things possible. Of course C++ doesn't support them, it is done via Qt metatype system. When D goes popular, IDEs will severely lack this functionality from the language.

There have been a lot of discussions on this topic in the past but I can't recall any conclusions. Perhaps some brave soul would dare to write a DIP on properties?


July 23, 2009
Andrei Alexandrescu wrote:
> Rainer Deyke wrote:
>> Yes, C++ has problems, but these problems can be fixed!
> 
> How? Minding constantly a set of dangerous problems is not fixing it.

Proposal 1: instances of polymorphic classes are stored on the heap but treated as value types.  They are copied when the variable is copied (a full non-slicing copy), they are destroyed when the variable goes out of scope.  In short, they are truly polymorphic value types, with some performance penalty.

Proposal 2: Syntactically distinguish between polymorphic references (references to an instance of a  class or any of its subclasses) and non-polymorphic references (references to an instance of a specific class and only that class), with the latter decaying to the former. Copy constructors would take a non-polymorphic reference as argument, thereby completely fixing the slicing problem.

>> The
>> struct/class split, on the other hand, introduces many more problems
>> that are harder to fix.
> 
> Again: what are those problems?

Syntactic ambiguity.  Confusion between an instance of a class and a reference to that instance.


-- 
Rainer Deyke - rainerd@eldwood.com
July 23, 2009
Jarrett Billingsley wrote:
> Classes and structs are fundamentally different concepts.  You design your code from the start to use one or the other, because only one makes sense.

In my first (and to date only) D project, *all* my user-defined types started as structs, and *all* became classes when I found out that D1 structs don't support all of the features I need.  (None of them used polymorphism.  In C++, all would have been value types.)

I expect the situation will be much better in D2.


-- 
Rainer Deyke - rainerd@eldwood.com
July 23, 2009
"Knud Soerensen" <4tuu4k002@sneakemail.com> wrote in message news:h49mfs$vf2$1@digitalmars.com...
>
> Some time ago I need a script to get and process some data.
> I trough why not use D, but I couldn't find a function in the standard
> library which would get a simple web page with http.
> Instead of find and downloading other libraries I switched to peal and had
> it running in no time.
>
.....
>
> ** Unit test isolation
> I would like to be able to isolate the unit test,
> so that if one fail the next still runs.
>

You may want to keep an eye on my SemiTwist D Tools http://www.dsource.org/projects/semitwist/

I haven't gotten around to releasing it yet, but it includes an alternate to assert that delays the "exit app" until you tell it to:

int x = 7;
mixin(deferAssert!("x == 9"));
mixin(deferAssert!("2+2==5", "Reality is broken"));
flushAsserts(); // Can put this at the beginning of main to wait for all
unittests to run before bailing.
// Now you get both errors, not just the first one.

Unfortunately I wasn't able to get around the awkward "mixin" part though. (It also doesn't seem to work inside in{} out{} blocks, not sure why yet, I think there may be some limitation I'm not aware of about the code allowed in those.)

In the same project I'm also working on a library that will provide, with one import, a full kitchen-sink scripting-style environment that should make the tasks like your example above much much easier in D.


July 23, 2009
Walter Bright wrote:

> Michiel Helvensteijn wrote:
...
>> * No control over their use by class designer: ANY member function with one or zero parameters may be called using 'property syntax'. This is not a good thing.
> 
> Why not? Seriously, what is the semantic difference?

The major point about properties is imo not a semantic issue at all, it's about signalling the intention (much like the debug version statement is). This is also key to integration with tools like IDE and it's usefulness in gui programming.


July 23, 2009
On Thu, Jul 23, 2009 at 4:34 PM, Rainer Deyke<rainerd@eldwood.com> wrote:
> Jarrett Billingsley wrote:
>> Classes and structs are fundamentally different concepts.  You design your code from the start to use one or the other, because only one makes sense.
>
> In my first (and to date only) D project, *all* my user-defined types started as structs, and *all* became classes when I found out that D1 structs don't support all of the features I need.  (None of them used polymorphism.  In C++, all would have been value types.)

And you don't think that has *anything* to do with trying to program C++ in D.