August 17, 2007
Walter Bright wrote:
> James Dennett wrote:
>> For one, rather restricted, notion of OOP.  There are many, many views of what constitutes OOP in the PL community.
> 
> The definition I use is a common one, OOP design consists of three characteristics:
> 
> 1) inheritance
> 2) polymorphism
> 3) encapsulation

Then objects are in no way disallowed from having value semantics.

>>> In C++, an OOP class can be used/misused by the user as a value type or a reference type, all out of the purview of the class designer. The class designer must control this, not the class user.
>>
>> It's normal in C++ to make "entity" classes (those that you're calling reference types) noncopyable.  It's also normal to make base classes abstract.  Thus idioms easily prevent the basic misuses.
> 
> C++ is loaded with idioms and conventions to try and head off major problems. I'd rather snip off such problems at the source - for one reason, it will dramatically reduce the learning curve of the language. For another, the more guarantees the language can offer, the lesser a burden it is on the code auditor, and the more likely the code is to be correct.

Valid points, though removing expressive power tends to move the complexity into code, and it's hard to remove the power to write bad code without also removing the power to write great code.

-- James

August 17, 2007
Walter Bright wrote:
> Robert Fraser wrote:
>> Making something part of the language
>> standardizes it. That's why having unittests, asserts, preconditions,
>> etc., in D is such a boon: while that could all be done using a
>> library, there'd probably be three or four different libraries out
>> there to do it and 75% of users wouldn't know about them or use those
>> features at all.
> 
> Right on.
> 

It's true; one problem with C++ is that there is too much
diversity in the (huge) set of idioms and libraries, and
standardization has many benefits (which is why it's
something I work on).  Sometimes it *can* even be better
to have one preferred approach to something even if it's
not technically the greatest, for the other benefits that
it can bring.

With the complexity of C++, it's a real problem finding developers with enough knowledge to use it safely and efficiently (more so than for C, in my experience, though the best C++ runs rings around C).  Simplicity and uniformity has great merit, but does require taking calculated risks and making trade-offs.

-- James
August 17, 2007
Walter Bright wrote:
> James Dennett wrote:
>> Walter Bright wrote:
>>> That's known as the 'slicing' problem. It's pernicious in that it can be extremely hard to expose via testing or code reviews, yet will expose the program to unpredictable behavior.
>>
>> It's trivially detected by various automated tools, which can flag any non-abstract base class.  (Such classes almost invariably indicate bad design in any case.)  Clearly it would be simple for a compiler to detect when a concrete class was used as a base class.  There's no need to remove value semantics in order to solve this problem; it's something of a sledgehammer solution.
> 
> That's true if you agree with the notion that only abstract classes should be used as base classes, which I do not agree with.

Then you lose benefits of static type checking for operations such as equality comparisons, unless you have ugly special cases.  How does D handle this?  Guess I'll go look it up.

-- James
August 17, 2007
Walter Bright wrote:
> James Dennett wrote:
>> Walter Bright wrote:
>>> Value types are fundamentally different from reference types. D gives you the choice.
>>
>> C++ gives you *more* choice by allowing easier migration between the two without imposing performance or syntactic differences.
> 
> That isn't my experience. In my work on DMDscript in D, I changed some types between struct and class to try out some variations, and found it to be a lot easier than in C++. For one thing, I didn't have to find and edit all the -> and .'s.

In C++, no, you didn't, as structs and classes are no different in their use of "->" and "." (as you're aware, they're all just classes).

Now, if you changed from using objects by value to using them by reference, it would be dangerous to take the D route and use almost the same syntax for both (for example, you inherit the ubiquitous Java bug of writing MyType foo; and finding that foo is null rather than being a usable object).

Of course there are two things being conflated here:
(1) the difference between structs and classes, and
(2) the difference between entity/reference types and value types

In D, this "confusion" is not a confusion, as struct/class are there to model the latter distinction.  In C++, you can take entity objects and drop them on the stack (in perfectly sane code), and you can take value objects and work with them on the heap (as you can in D, I believe); it makes the two dimensions orthogonal.

(This has an analog in access control: in C++ access control and virtual-ness are orthogonal, in Java and D they are not. Orthogonality has advantages, but also has some consequences that are arguably counter-intuitive.)

> But you're right that C++ allows you more choice - you can create a polymorphic type with value semantics. I think D is better off without them, however.

Your call.  I don't agree, but that's fine!

-- James
August 17, 2007
Walter Bright wrote:
> eao197 wrote:
>>  From my expirience this is a problem of C++ beginners.
> 
> I was talking to a person who is a C++ developer for a major game company just today. He told me that it is very difficult to find experienced C++ developers, hire them, or even recognize them in a job interview. When you are able to hire them, they cost plenty.

An important observation.  And given that programmers starting out in their careers are often looking at more "modern" languages, the pool of competent C++ developers isn't growing fast, while demand is still pretty strong.

> It's true that every problem with C++ can be solved by getting more advanced C++ programmers. The problem is getting those C++ programmers. And even the best ones have bad days and make mistakes <g>.

I assure you, on bad days I have made mistakes in many, many languages ;)

> Defining a problem out of existence is preferable, cheaper, and more reliable than depending on convention or more training.
> 
> If I was paying top dollar for a programming expert, I'd rather he focused his energies on something more productive than dodging C++'s potholes.

And if you get an expert who knows C++, she won't spend much time avoiding its potholes.

> If I was in charge of writing software that absolutely, positively must work correctly, I'll prefer a language guarantee over reliance that my programmers, no matter how good they are, didn't overlook something.

Yup; I look forward to a future in which correctness proofs play a larger role in practical situations.

-- James
August 17, 2007
James Dennett wrote:
> Walter Bright wrote:
>> James Dennett wrote:
>>> For one, rather restricted, notion of OOP.  There are many,
>>> many views of what constitutes OOP in the PL community.
>> The definition I use is a common one, OOP design consists of three
>> characteristics:
>>
>> 1) inheritance
>> 2) polymorphism
>> 3) encapsulation
> 
> Then objects are in no way disallowed from having value semantics.

And there are situations where they can even be true values, without encountering slicing problems.

It always irked me that in C++ there's no natural way of having polymorphic value types. (And D hasn't changed this).
The case where you have

class Base {
 int a_;
 int b_;
public:
virtual int func() { ... } // use a_ and b_
};

class Derived : public Base {
 virtual int func() { ... }
};

And the interesting thing about Derived is that it only adds an interface, not data. It's kind of like a abstract base class, in reverse.
An instance of Derived is just a Base, but with a different value in the hidden vtable parameter.

If a derived class does not add any data members (or multiple inheritance), then there's never a slicing problem. You can have a container of polymorphic classes, stored as values, with perfect safety.

I this is a pretty common scenario, but there's no language support for it.
Would be great to be able to say 'any class derived from this class is not permitted to add data' -- abstract derivations only.
August 17, 2007
Walter Bright Wrote:

> 1) inheritance
> 2) polymorphism
> 3) encapsulation

Another one in that list should be "reference", which IMO would be assumed by most people, but has been lost with transitive const in D.
I would define it as the ability to not encapsulate something a class has a reference to.
By making all objects that an object has references to necessarily part of that object, the transitive const feature means that the only state relationship a class can have to another class is encapsulation.

Correct me if i'm wrong :)
August 17, 2007
"eao197" <eao197@intervale.ru> wrote in message
news:op.tw6uouycsdcfd2@eao197nb2.intervale.ru...
On Thu, 16 Aug 2007 22:36:53 +0400, Walter Bright
<newshound1@digitalmars.com> wrote:
>But let to return to your goal: "Defining a problem out of existence is preferable, cheaper, and more reliable than depending on convention or more training." How about eluminating such problem as null pointers (I think it is much more common and dangerous problem than object slicing).

Because null pointers are easy to debug. And it's a lot less dangerous because you get an exception generated when you try to use a null pointer.

Where as with the slicing problem anything can happen and it's incredibly hard to debug.



August 17, 2007
Agreed, but I can't think of another language that supports this definition of OOP (apart from 'mutable' under C++ - which is widely regarded as a hack).

Alex Burton wrote:
> Walter Bright Wrote:
> 
>> 1) inheritance
>> 2) polymorphism
>> 3) encapsulation
> 
> Another one in that list should be "reference", which IMO would be assumed by most people, but has been lost with transitive const in D.
> I would define it as the ability to not encapsulate something a class has a reference to.
> By making all objects that an object has references to necessarily part of that object, the transitive const feature means that the only state relationship a class can have to another class is encapsulation.
> 
> Correct me if i'm wrong :)
August 17, 2007
On Fri, 17 Aug 2007 18:58:19 +0400, Jb <jb@nowhere.com> wrote:

>
> "eao197" <eao197@intervale.ru> wrote in message
> news:op.tw6uouycsdcfd2@eao197nb2.intervale.ru...
> On Thu, 16 Aug 2007 22:36:53 +0400, Walter Bright
> <newshound1@digitalmars.com> wrote:
>> But let to return to your goal: "Defining a problem out of existence is
>> preferable, cheaper, and more reliable than depending on convention or
>> more training." How about eluminating such problem as null pointers (I
>> think it is much more common and dangerous problem than object slicing).
>
> Because null pointers are easy to debug. And it's a lot less dangerous
> because you get an exception generated when you try to use a null pointer.

It is, probably, a good consolidation when null-pointer error happens in production code.

> Where as with the slicing problem anything can happen and it's incredibly
> hard to debug.

Any examples? What's bad and dangerous happens in the case of slicing?

-- 
Regards,
Yauheni Akhotnikau