View mode: basic / threaded / horizontal-split · Log in · Help
August 04, 2012
@property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Re: @property
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
Top | Discussion index | About this forum | D home