Jump to page: 1 25  
Page
Thread overview
@property
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Adam D. Ruppe
Aug 05, 2012
bearophile
Aug 05, 2012
Adam D. Ruppe
Aug 05, 2012
Jonathan M Davis
Aug 05, 2012
bearophile
Aug 05, 2012
Jonathan M Davis
Aug 05, 2012
Adam D. Ruppe
Aug 05, 2012
Dmitry Olshansky
Aug 05, 2012
Simen Kjaeraas
Aug 05, 2012
bearophile
Aug 05, 2012
Adam D. Ruppe
Aug 05, 2012
bearophile
Aug 05, 2012
Kapps
Aug 07, 2012
Timon Gehr
Aug 07, 2012
Jacob Carlborg
Aug 07, 2012
Timon Gehr
Aug 07, 2012
Timon Gehr
Aug 07, 2012
Brad Anderson
Aug 07, 2012
Brad Anderson
Aug 05, 2012
Jonathan M Davis
Aug 04, 2012
deadalnix
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Jacob Carlborg
Aug 04, 2012
Jacob Carlborg
Aug 04, 2012
Jonathan M Davis
Aug 05, 2012
Jacob Carlborg
Aug 05, 2012
Jacob Carlborg
Aug 04, 2012
Adam D. Ruppe
Aug 05, 2012
Jacob Carlborg
Aug 05, 2012
Adam D. Ruppe
Aug 05, 2012
Jacob Carlborg
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Jonathan M Davis
Aug 04, 2012
Adam D. Ruppe
Aug 05, 2012
Jacob Carlborg
Aug 05, 2012
Jacob Carlborg
Aug 05, 2012
Adam D. Ruppe
Aug 06, 2012
Michael
Aug 04, 2012
Chad J
Aug 04, 2012
Adam D. Ruppe
Aug 04, 2012
Chad J
Aug 07, 2012
Jonathan M Davis
August 04, 2012
So the existing -property in the compiler as absolutely worthless. It is semantically wrong.

@property void function() func() {
        return { assert(0, "success"); };
}

void main() {
        func(); // should assert 0 success, doesn't
	auto dele = &func;
	dele(); // should assert 0 success, doesn't
}

Does the same thing with and without -property, and it is
wrong both ways.


Now, let's talk about doing it right. First, I think the entire
getter design in the compiler is counter productive. It looks
like it is part of the AssignExp... but you want getters to work
in a lot of places, not just AssignExp.



It looks to me that it actually belongs in the resolveProperties function in expression.c, or maybe even somewhere else since I tried this and it didn't quite work. I think this is operating on a whole line, not just the individual pieces. But regardless, it definitely belongs on a lower level than it is.



See, if you ask me, every single mention of a function name that is marked @property needs to be rewritten. This might break setters, but we'll cross that bridge when we come to it.


When we look back at the test code:

        func(); // should assert 0 success, doesn't
	auto dele = &func;


These two lines both currently refer to the getter function
itself. We want the getter function to be completely invisible
to all other code.


This should be rewritten kinda like if this were in the code:
  #define func (func())


This would also fix things like

func += 10;

if func returned a ref int.

===
@property ref int func() {
        static int a;
        return a;
}

void main() {
        // all of these should work; func should look just like an int to the outside world
        int a = func;
        int* b = &func;
        func += 10;
}
===
callexp.d(19): Error: cannot implicitly convert expression (& func) of type int function() @property ref to int*




Let's try running our "macro" over it

void main() {
        int a = (func());
        int* b = &(func());
        (func()) += 10;
}


What ACTUALLY happens right now is that works. Indeed, you HAVE to use the () right now to make it work!


What SHOULD happen:

callexp.d(18): Error: function expected before (), not func() of type int
callexp.d(20): Error: function expected before (), not func() of type int

Or something like that. Since @property ref int func() is supposed to be interchangable for a plain int func;, no special enforcement of @property syntax is required: it is illegal to call an int like a function, and func is an int as far as the outside world is concerned.


This is how the property syntax is enforced: by the compiler's existing type checks. No additional code should be there to check syntax.





So, I have two questions:

1) Do we all agree that @properties should be interchangeable for plain variables of the return value's type in all contexts? That is, if I can make this work with a pull request, is that going to be acceptable?

2) Does anyone who knows the compiler better want to give me some hints on the implementation? I'm still pretty sure the resolveProperties function is too far into it, but func on its own is just a void* to the function I believe at this point so... yeah that is complicating things. Perhaps *that* is what needs to change.


I'm also open to ideas on setters, but right now getter is what I want to focus on. If we have to rewrite a getter call on the left hand side of an assign exp into a setter call, we can figure that out later. Hell, it might even just work.  But one thing at a time.
August 04, 2012
I should add: if a function is not marked @property, it should not change at all: it should be callable with and without parens, including sometimes referring to the wrong thing, exactly like it is now.

I come to fix code, not to break it. Rewriting references to @property function names should fix all property related issues without breaking any existing code (except that which explicitly specified @property but depended on the wrong semantics, code which is arguably already broken, just like any other bug fix can do.)
August 04, 2012
Le 04/08/2012 19:13, Adam D. Ruppe a écrit :
> So the existing -property in the compiler as absolutely worthless. It is
> semantically wrong.
>
> @property void function() func() {
> return { assert(0, "success"); };
> }
>
> void main() {
> func(); // should assert 0 success, doesn't
> auto dele = &func;
> dele(); // should assert 0 success, doesn't
> }
>
> Does the same thing with and without -property, and it is
> wrong both ways.
>

Note that something more is wrong.
func(); // Do something
auto dele = &func;
dele(); // Expected to do the same thing, even if we passed throw & in the middle.

The whole thing is f***ed up IMO. (and I've made some work on SDC on the subject, the & is really convoluted to implement).

> When we look back at the test code:
>
> func(); // should assert 0 success, doesn't
> auto dele = &func;
>

auto dele = func;

> These two lines both currently refer to the getter function
> itself. We want the getter function to be completely invisible
> to all other code.
>
>
> This should be rewritten kinda like if this were in the code:
> #define func (func())
>
>
> This would also fix things like
>
> func += 10;
>
> if func returned a ref int.
>
> What SHOULD happen:
>
> callexp.d(18): Error: function expected before (), not func() of type int
> callexp.d(20): Error: function expected before (), not func() of type int
>

+1

> Or something like that. Since @property ref int func() is supposed to be
> interchangable for a plain int func;, no special enforcement of
> @property syntax is required: it is illegal to call an int like a
> function, and func is an int as far as the outside world is concerned.
>

+1

> 1) Do we all agree that @properties should be interchangeable for plain
> variables of the return value's type in all contexts? That is, if I can
> make this work with a pull request, is that going to be acceptable?
>

Except for that & thing, 100% agreed.
August 04, 2012
On Saturday, 4 August 2012 at 17:35:03 UTC, deadalnix wrote:
> Except for that & thing, 100% agreed.

I think you're right about that too...


August 04, 2012
I think I've cracked the getters...

I opened expression.c in DMD and surfed to line 2940 or so. Looks like this:

        {
            error("forward reference to %s", toChars());
            return new ErrorExp();
        }

        return new VarExp(loc, f, hasOverloads);


The function is



Expression *DsymbolExp::semantic(Scope *sc)


Instead of return new VarExp, I made it:


        VarExp* varexp = new VarExp(loc, f, hasOverloads);

        TypeFunction* tf = (TypeFunction *)f->type;
        if(tf->isproperty) {
            CallExp* ce = new CallExp(loc, varexp);
            ce->semantic(sc);
            return ce;
        } else {
            return varexp;
        }




And now my test functions work... the question is, did I break a lot of other stuff? idk, but this is a big move forward.
August 04, 2012
On 2012-08-04 19:13, Adam D. Ruppe wrote:

> This would also fix things like
>
> func += 10;
>
> if func returned a ref int.
>
> ===
> @property ref int func() {
>          static int a;
>          return a;
> }
>
> void main() {
>          // all of these should work; func should look just like an int
> to the outside world
>          int a = func;
>          int* b = &func;
>          func += 10;
> }
> ===
> callexp.d(19): Error: cannot implicitly convert expression (& func) of
> type int function() @property ref to int*

I don't think that's correct behavior. I think the correct behavior would be to have a property rewrite, something like this:

foo += 10;

Is rewritten as:

auto __tmp = foo;
foo = __tmp + 10;

> Or something like that. Since @property ref int func() is supposed to be
> interchangable for a plain int func;, no special enforcement of
> @property syntax is required: it is illegal to call an int like a
> function, and func is an int as far as the outside world is concerned.
>
> This is how the property syntax is enforced: by the compiler's existing
> type checks. No additional code should be there to check syntax.
>
> So, I have two questions:
>
> 1) Do we all agree that @properties should be interchangeable for plain
> variables of the return value's type in all contexts? That is, if I can
> make this work with a pull request, is that going to be acceptable?

I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.

-- 
/Jacob Carlborg
August 04, 2012
On 2012-08-04 21:08, Jacob Carlborg wrote:

> I think that you should always be able to replace a variable with a
> property. The other way around I'm not so sure. The problem is with
> methods in classes. Since a method will be virtual by default you can't
> just replace a property with a variable. That could potentially break
> subclasses that override the property.

I wouldn't actually mind a way to do this, perhaps something like this:

class Foo
{
    @property int bar:
}

Would be the same as:

class Foo
{
    private int bar_:
    @property int bar () { return bar_; }
    @property int bar (int value) { return bar_ = value; }
}

-- 
/Jacob Carlborg
August 04, 2012
On Saturday, 4 August 2012 at 19:08:58 UTC, Jacob Carlborg wrote:
> I don't think that's correct behavior. I think the correct behavior would be to have a property rewrite, something like this:

Yes, I agree in general, but if a getter returns a ref, you should
be able to write to it... I think anyway, but it is an lvalue anyway.


What I just added to my hacked compiler is this:

=====
 else if(e1->op == TOKcall) {
            // for property work, if there is a setter, we should revert to the older style
            // handling. If not, we can keep it as a CallExp
            CallExp* ce = (CallExp*) e1;
            Expression* temp_e1 = ce->e1;
            if((temp_e1->op == TOKvar && temp_e1->type->toBasetype()->ty == Tfunction)) {
                // this is potentially a setter.... but not necessarily
                fd = ((VarExp *)temp_e1)->var->isFuncDeclaration();
                ethis = NULL;
                assert(fd);
                FuncDeclaration *f = fd;
                Expressions a;
                a.push(e2);

                fd = f->overloadResolve(loc, ethis, &a, 1);
                if (fd && fd->type) {
                    e1 = temp_e1;
                    goto Lsetter;
                }
            }
=====


To line 10320 - right above where the old style setter code is. It isn't perfect yet because it doesn't ensure we are dealing with a @property, but it is closer.



The idea is: if we have a setter function, we should try to use it, just like dmd does today. If not, we'll leave the call there and see what happens. (If it returns ref, it will work, otherwise, it errors saying the property is not an lvalue.)


So far this is passing my simple test for assignment, but not yet the op assigns.

int a;
@property int funcprop() {
        return a;
}

// setter
@property int funcprop(int s) {
        return a = s + 10;
}

funcprop = 10; // works, funcprop == 20 now
funcprop += 10; // currently does NOT work


> Is rewritten as:
>
> auto __tmp = foo;
> foo = __tmp + 10;

I think this is exactly what we have to do to work in all cases. I'm gonna take a look at it next... then it is time to test this patch and with a little luck, we can finally put the property debate to rest.


> I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.

True. I think all the other uses should just work though.
August 04, 2012
On Saturday, August 04, 2012 21:11:47 Jacob Carlborg wrote:
> On 2012-08-04 21:08, Jacob Carlborg wrote:
> > I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.
> 
> I wouldn't actually mind a way to do this, perhaps something like this:
> 
> class Foo
> {
>      @property int bar:
> }
> 
> Would be the same as:
> 
> class Foo
> {
>      private int bar_:
>      @property int bar () { return bar_; }
>      @property int bar (int value) { return bar_ = value; }
> }1

That would be kind of cool, though I would have suggested that putting @property on a variable would make it so that you couldn't do anything with it that you couldn't do with a property (e.g. taking the address of a variable will break when it's switched to a property, and @property on the variable could prevent that). But maybe your proposal is better - though I'm not sure how much I'd end up using it, because if you wanted to actually use the member variable, you'd get into naming issues. You proposed bar_ here, but I'd have gone with _bar, whereas some would have suggested m_bar, and regardless, there's no way to indicate the name with this syntax, so you'd have to either just know how the compiler names such variables or statically disallow using the property through anything other than the proprty functions. And if all the property does is get and set with _nothing_ else, then how is that any better than a public member variable, assuming that switching between a variable and a property is seemless like it's supposed to be? So, I think that I'd still prefer the approach of making it so that marking variables @property makes it so that you can only use them in ways that you can use a property function, since it gives you the same result without needing to actually create any functions or come up with naming schemes for implicit member variables or whatnot.

- Jonathan M Davis
August 04, 2012
On Saturday, 4 August 2012 at 19:08:58 UTC, Jacob Carlborg wrote:
> foo += 10;
>
> Is rewritten as:
>
> auto __tmp = foo;
> foo = __tmp + 10;


I did this and now I think this thing is almost done

===
int a;
@property int funcprop() {
        writeln("calling the getter and getting ", a);
	return a;
}
@property int funcprop(int s) {
	writeln("calling the setter with ", s);
	return a = s;
}
void main() {
	funcprop = 40;
	funcprop += 10;
}
===

run:

calling the setter with 40
calling the getter and getting 40
calling the setter with 50




Looks right to me. Now I just have to check for the @property tag on some of these rewrites and then clean it up and test for a pull request.
« First   ‹ Prev
1 2 3 4 5