Jump to page: 1 213  
Page
Thread overview
Inheritance of purity
Feb 17, 2012
Walter Bright
Feb 17, 2012
H. S. Teoh
Feb 17, 2012
Jacob Carlborg
Feb 17, 2012
Iain Buclaw
Feb 17, 2012
Jacob Carlborg
Feb 17, 2012
James Miller
Feb 17, 2012
Jonathan M Davis
Feb 17, 2012
Walter Bright
Feb 17, 2012
Jonathan M Davis
Feb 17, 2012
Walter Bright
Feb 17, 2012
Walter Bright
Feb 17, 2012
Timon Gehr
Feb 18, 2012
deadalnix
Feb 17, 2012
H. S. Teoh
Feb 17, 2012
Marco Leise
Feb 17, 2012
bearophile
Feb 17, 2012
Timon Gehr
Feb 17, 2012
Timon Gehr
Feb 17, 2012
Walter Bright
Feb 17, 2012
Kapps
Feb 23, 2012
Bruno Medeiros
Feb 17, 2012
Piotr Szturmaj
Feb 17, 2012
Gor Gyolchanyan
Feb 17, 2012
Piotr Szturmaj
Feb 17, 2012
Gor Gyolchanyan
Feb 17, 2012
Piotr Szturmaj
Feb 17, 2012
Piotr Szturmaj
Feb 17, 2012
Timon Gehr
Feb 17, 2012
dsimcha
Feb 23, 2012
so
Feb 23, 2012
F i L
Feb 23, 2012
so
Feb 24, 2012
F i L
Feb 24, 2012
so
Feb 24, 2012
Alix Pexton
Feb 24, 2012
Walter Bright
Feb 24, 2012
David
Feb 24, 2012
Alix Pexton
Feb 24, 2012
Robert Clipsham
Feb 24, 2012
H. S. Teoh
Feb 25, 2012
Sean Cavanaugh
Feb 25, 2012
so
Feb 26, 2012
deadalnix
Feb 26, 2012
so
Feb 26, 2012
Daniel Murphy
Feb 26, 2012
so
Feb 26, 2012
Daniel Murphy
Feb 23, 2012
H. S. Teoh
Feb 24, 2012
F i L
Feb 24, 2012
James Miller
Feb 25, 2012
foobar
Feb 26, 2012
James Miller
Feb 26, 2012
foobar
Feb 24, 2012
H. S. Teoh
Feb 25, 2012
foobar
Feb 17, 2012
Michel Fortin
Feb 17, 2012
Timon Gehr
Feb 17, 2012
F i L
Feb 17, 2012
Timon Gehr
Feb 17, 2012
Timon Gehr
Feb 17, 2012
kenji hara
Feb 17, 2012
Timon Gehr
Feb 17, 2012
Timon Gehr
Feb 18, 2012
deadalnix
Feb 17, 2012
kenji hara
Feb 24, 2012
deadalnix
Feb 25, 2012
Walter Bright
Feb 26, 2012
deadalnix
Feb 26, 2012
Daniel Murphy
Feb 17, 2012
Martin Nowak
Feb 17, 2012
Michal Minich
Feb 17, 2012
H. S. Teoh
Feb 17, 2012
Walter Bright
Feb 18, 2012
deadalnix
Feb 18, 2012
Timon Gehr
Feb 18, 2012
deadalnix
Feb 18, 2012
Timon Gehr
Feb 20, 2012
Gor Gyolchanyan
Feb 24, 2012
deadalnix
Feb 18, 2012
kenji hara
Feb 18, 2012
Walter Bright
Feb 24, 2012
deadalnix
Feb 25, 2012
Timon Gehr
Feb 25, 2012
deadalnix
Feb 25, 2012
Timon Gehr
Feb 25, 2012
so
Feb 25, 2012
Timon Gehr
Feb 25, 2012
Walter Bright
Feb 25, 2012
deadalnix
Feb 25, 2012
Timon Gehr
Feb 25, 2012
deadalnix
Feb 25, 2012
Walter Bright
Feb 25, 2012
deadalnix
Feb 25, 2012
Walter Bright
Feb 26, 2012
deadalnix
Feb 26, 2012
Jonathan M Davis
Feb 26, 2012
deadalnix
Feb 26, 2012
Jonathan M Davis
Feb 26, 2012
Jonathan M Davis
Feb 23, 2012
Bruno Medeiros
Feb 23, 2012
Walter Bright
Feb 23, 2012
so
Feb 24, 2012
deadalnix
Feb 23, 2012
Jason House
Feb 23, 2012
H. S. Teoh
Feb 23, 2012
so
Feb 23, 2012
so
Feb 24, 2012
Jonathan M Davis
Feb 24, 2012
H. S. Teoh
Feb 26, 2012
Jason House
Feb 26, 2012
Timon Gehr
February 17, 2012
Given:

    class A { void foo() { } }
    class B : A { override pure void foo() { } }

This works great, because B.foo is covariant with A.foo, meaning it can "tighten", or place more restrictions, on foo. But:

    class A { pure void foo() { } }
    class B : A { override void foo() { } }

fails, because B.foo tries to loosen the requirements, and so is not covariant.

Where this gets annoying is when the qualifiers on the base class function have to be repeated on all its overrides. I ran headlong into this when experimenting with making the member functions of class Object pure.

So it occurred to me that an overriding function could *inherit* the qualifiers from the overridden function. The qualifiers of the overriding function would be the "tightest" of its explicit qualifiers and its overridden function qualifiers. It turns out that most functions are naturally pure, so this greatly eases things and eliminates annoying typing.

I want do to this for @safe, pure, nothrow, and even const.

I think it is semantically sound, as well. The overriding function body will be semantically checked against this tightest set of qualifiers.

What do you think?
February 17, 2012
On Thu, Feb 16, 2012 at 06:49:40PM -0800, Walter Bright wrote: [...]
> So it occurred to me that an overriding function could *inherit* the qualifiers from the overridden function. The qualifiers of the overriding function would be the "tightest" of its explicit qualifiers and its overridden function qualifiers. It turns out that most functions are naturally pure, so this greatly eases things and eliminates annoying typing.

I like this idea.


> I want do to this for @safe, pure, nothrow, and even const.

Excellent!


> I think it is semantically sound, as well. The overriding function body will be semantically checked against this tightest set of qualifiers.
> 
> What do you think?

Semantically, it makes sense. And reducing typing is always good. (That's one of my pet peeves about Java: too much typing just to achieve something really simple. It feels like being forced to kill a mosquito with a laser-guided missile by specifying 3D coordinates accurate to 10 decimal places.)

The one disadvantage I can think of is that it will no longer be clear exactly what qualifiers are in effect just by looking at the function definition in a derived class. Which is not terrible, I suppose, but I can see how it might get annoying if you have to trace the overrides all the way up the inheritance hierarchy just to find out what qualifiers a function actually has.

OTOH, if ddoc could automatically fill in the effective qualifiers, then this will be a non-problem. ;-)


T

-- 
Frank disagreement binds closer than feigned agreement.
February 17, 2012
On 17 February 2012 15:49, Walter Bright <newshound2@digitalmars.com> wrote:
> Given:
>
>    class A { void foo() { } }
>    class B : A { override pure void foo() { } }
>
> This works great, because B.foo is covariant with A.foo, meaning it can "tighten", or place more restrictions, on foo. But:
>
>    class A { pure void foo() { } }
>    class B : A { override void foo() { } }
>
> fails, because B.foo tries to loosen the requirements, and so is not covariant.
>
> Where this gets annoying is when the qualifiers on the base class function have to be repeated on all its overrides. I ran headlong into this when experimenting with making the member functions of class Object pure.
>
> So it occurred to me that an overriding function could *inherit* the qualifiers from the overridden function. The qualifiers of the overriding function would be the "tightest" of its explicit qualifiers and its overridden function qualifiers. It turns out that most functions are naturally pure, so this greatly eases things and eliminates annoying typing.
>
> I want do to this for @safe, pure, nothrow, and even const.
>
> I think it is semantically sound, as well. The overriding function body will be semantically checked against this tightest set of qualifiers.
>
> What do you think?

Makes sense to me, should also ease some pains that I've seen discussed in other threads regarding the utility of pure and const, etc. In terms of intuitiveness, I think this makes more sense, since overrides are explicit.

I'm with Teoh that it might make it a bit more difficult to understand code, but to some extent that is partially a documentation problem, which is always an issue, no matter what.

--
James Miller
February 17, 2012
On Thursday, February 16, 2012 18:49:40 Walter Bright wrote:
> Given:
> 
>      class A { void foo() { } }
>      class B : A { override pure void foo() { } }
> 
> This works great, because B.foo is covariant with A.foo, meaning it can "tighten", or place more restrictions, on foo. But:
> 
>      class A { pure void foo() { } }
>      class B : A { override void foo() { } }
> 
> fails, because B.foo tries to loosen the requirements, and so is not covariant.
> 
> Where this gets annoying is when the qualifiers on the base class function have to be repeated on all its overrides. I ran headlong into this when experimenting with making the member functions of class Object pure.
> 
> So it occurred to me that an overriding function could *inherit* the qualifiers from the overridden function. The qualifiers of the overriding function would be the "tightest" of its explicit qualifiers and its overridden function qualifiers. It turns out that most functions are naturally pure, so this greatly eases things and eliminates annoying typing.
> 
> I want do to this for @safe, pure, nothrow, and even const.
> 
> I think it is semantically sound, as well. The overriding function body will be semantically checked against this tightest set of qualifiers.
> 
> What do you think?

No. Absolutely not. I hate the fact that C++ does this with virtual. It makes it so that you have to constantly look at the base classes to figure out what's virtual and what isn't. It harms maintenance and code understandability. And now you want to do that with @safe, pure, nothrow, and const? Yuck.

I can understand wanting to save some typing, but I really think that this harms code maintainability. It's the sort of thing that an IDE is good for. It does stuff like generate the function signatures for you or fill in the attributes that are required but are missing. I grant you that many D developers don't use IDEs at this point (at least not for D) and that those sort of capabilities are likely to be in their infancy for the IDEs that we _do_ have, but I really think that this is the sort of thing that should be left up to the IDE. Inferring attribtutes like that is just going to harm code maintainibility. It's bad enough that we end up with them not being marked on templates due to inferrence, but we _have_ to do it that way, because the attributes vary per instantiation. That is _not_ the case with class member functions.

Please, do _not_ do this.

- Jonathan M Davis
February 17, 2012
On 2/16/2012 7:23 PM, Jonathan M Davis wrote:
> No. Absolutely not. I hate the fact that C++ does this with virtual. It makes
> it so that you have to constantly look at the base classes to figure out what's
> virtual and what isn't. It harms maintenance and code understandability. And
> now you want to do that with @safe, pure, nothrow, and const? Yuck.

I do not see how it harms maintainability. It does not break any existing code. It makes it easier to convert a function hierarchy to nothrow, pure, etc.
February 17, 2012
On Thursday, February 16, 2012 19:41:00 Walter Bright wrote:
> On 2/16/2012 7:23 PM, Jonathan M Davis wrote:
> > No. Absolutely not. I hate the fact that C++ does this with virtual. It makes it so that you have to constantly look at the base classes to figure out what's virtual and what isn't. It harms maintenance and code understandability. And now you want to do that with @safe, pure, nothrow, and const? Yuck.
> I do not see how it harms maintainability. It does not break any existing code. It makes it easier to convert a function hierarchy to nothrow, pure, etc.

It makes it harder to maintain the code using the derived classes, because you end up with a bunch of functions which aren't labeled with their attributes. You have to go and find all of the base classes and look at them to find which attributes are on their functions to know what the attributes of the functions of the derived classes actually are. It will make using all D classes harder.

You should be able to look at a function and know whether it's pure, @safe, nothrow, or const without having to dig through documentation and/or code elsewhere to figure it out.

Doing this would make the conversion to const easier but be harmful in the long run.

- Jonathan M Davis
February 17, 2012
Jonathan M Davis:

> I hate the fact that C++ does this with virtual. It makes it so that you have to constantly look at the base classes to figure out what's virtual and what isn't. It harms maintenance and code understandability. And now you want to do that with @safe, pure, nothrow, and const? Yuck.

This is a problem.

On the other hand I presume Walter is now converting Phobos all at once to fix const correctness, so he's writing tons of attributes. So he desires to quicken this boring work.

On the other hand fixing const correctness in Phobos is not a common operation, I think it needs to be done only once. Once one or two future DMD versions are out, programmers will not need to introduce a large amount of those annotations at once. So "fixing" forever D2 for an operation done only once seems risky, especially if future IDEs will be able to insert those annotations cheaply.

So a possible solution is to wait 2.059 or 2.060 before introducing this "Inheritance of purity" idea. I think at that time we'll be more able to judge how much useful this feature is once Phobos is already fully const corrected and no need to fix a lot of code at once exists.

Another idea is to activate this "Inheritance of purity" only if you compile with "-d" (allow deprecated features) for few months and then remove it, to help porting of today D2 code to const correctness in a more gradual way.

Bye,
bearophile
February 17, 2012
On Thu, Feb 16, 2012 at 07:41:00PM -0800, Walter Bright wrote:
> On 2/16/2012 7:23 PM, Jonathan M Davis wrote:
> >No. Absolutely not. I hate the fact that C++ does this with virtual. It makes it so that you have to constantly look at the base classes to figure out what's virtual and what isn't. It harms maintenance and code understandability. And now you want to do that with @safe, pure, nothrow, and const? Yuck.
> 
> I do not see how it harms maintainability. It does not break any existing code. It makes it easier to convert a function hierarchy to nothrow, pure, etc.

It's probably the same reason I brought up: looking at a function's definition will no longer tell you which modifiers are actually in effect. So you have to trace the overrides up the inheritance hierarchy in order to know exactly what modifiers it has.

But again, if ddoc can automatically compute this for you, then it shouldn't be that much of an issue anymore, right?

On that note, though, one thing I've always wanted in a programming language is to be able to ask the compiler to expand all templates, deduce all types, etc., for a given function/declaration, and print out what it actually understands the declaration to be (as opposed to what I *think* the declaration would expand to). I know that in C/C++ you can preprocess the source, but it still doesn't expand typedefs, templates, etc.. Plus the S:N ratio is too low (nobody wants to wade through 5000 lines of preprocessed code just to find that one declaration).

If dmd (and its derivatives) has an option to do this, say perhaps
something like:

	$ dmd -query my.module.myclass.prop01 *.d
	my.module.myclass.prop01:
	my/module.d(123): @property pure lazy const int prop01(int x) { ... }
	$

then this should greatly ease Jonathan's objection to your proposal. (The current .di files might already sortof fill this purpose, although .di's have other problems that I don't really want to get into here.)


T

-- 
"I suspect the best way to deal with procrastination is to put off the procrastination itself until later. I've been meaning to try this, but haven't gotten around to it yet. " -- swr
February 17, 2012
On 2012-02-17 02:49:40 +0000, Walter Bright <newshound2@digitalmars.com> said:

> Given:
> 
>      class A { void foo() { } }
>      class B : A { override pure void foo() { } }
> 
> This works great, because B.foo is covariant with A.foo, meaning it can "tighten", or place more restrictions, on foo. But:
> 
>      class A { pure void foo() { } }
>      class B : A { override void foo() { } }
> 
> fails, because B.foo tries to loosen the requirements, and so is not covariant.
> 
> Where this gets annoying is when the qualifiers on the base class function have to be repeated on all its overrides. I ran headlong into this when experimenting with making the member functions of class Object pure.
> 
> So it occurred to me that an overriding function could *inherit* the qualifiers from the overridden function. The qualifiers of the overriding function would be the "tightest" of its explicit qualifiers and its overridden function qualifiers. It turns out that most functions are naturally pure, so this greatly eases things and eliminates annoying typing.
> 
> I want do to this for @safe, pure, nothrow, and even const.
> 
> I think it is semantically sound, as well. The overriding function body will be semantically checked against this tightest set of qualifiers.
> 
> What do you think?

Seems like a good idea to me.

But I think you should make sure error messages mentioning an implied inherited attribute says from which subclass the attribute was inherited from. For instance:

	override void foo() { impure(); }
	// -> error: cannot call impure() in pure function (purity inherited from A.foo)

I think such messages will ease code maintenance, because if you later edit foo() you might easily forget it is implicitly pure. With this message if you somehow need to remove purity you know where to look.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

February 17, 2012
On 02/17/2012 03:49 AM, Walter Bright wrote:
> Given:
>
> class A { void foo() { } }
> class B : A { override pure void foo() { } }
>
> This works great, because B.foo is covariant with A.foo, meaning it can
> "tighten", or place more restrictions, on foo. But:
>
> class A { pure void foo() { } }
> class B : A { override void foo() { } }
>
> fails, because B.foo tries to loosen the requirements, and so is not
> covariant.
>
> Where this gets annoying is when the qualifiers on the base class
> function have to be repeated on all its overrides. I ran headlong into
> this when experimenting with making the member functions of class Object
> pure.
>
> So it occurred to me that an overriding function could *inherit* the
> qualifiers from the overridden function. The qualifiers of the
> overriding function would be the "tightest" of its explicit qualifiers
> and its overridden function qualifiers. It turns out that most functions
> are naturally pure, so this greatly eases things and eliminates annoying
> typing.
>
> I want do to this for @safe, pure, nothrow, and even const.
>
> I think it is semantically sound, as well. The overriding function body
> will be semantically checked against this tightest set of qualifiers.
>
> What do you think?

Yes, please!
« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11