Hi, Nick,

Kudos for thinking outside the box!

On Sun, Sep 16, 2012 at 7:45 AM, Nick Wellnhofer <[email protected]> wrote:

> This leaves the problem of converting the members struct pointers from a
> source class to a target class for every method call. The obvious approach
> is to somehow work back to the start of the memory region of the object, and
> then apply an offset appropriate for the target class. Finding the the start
> of the object could be done by adding a field to every members struct. This
> would mean two additional fields if you want to keep direct vtable access
> (e.g. for method calls) from member structs. All of that looks rather
> expensive to me.

In addition to being expensive, it seems to me that it would also be complex and
error prone.  The proposal I made back in May, inspired by C++, was also
pretty labyrinthine, but if it had worked the way I'd hoped, the complexity
would have been hidden within the method dispatch apparatus -- from the
standpoint of the programmer, `self` would have always Just Worked.

I'm concerned about making programmers think about any invocant more
complicated than `self` on its own.  Getting at the `members` struct is also
kind of a pain, but at least it's an easily-understood, logical step and hard
to mess up.

> So in terms of what arguments a method could receive for the 'self' object,
> I can see the following solutions (in my order of preference):
>
> 1. Foo_set_num(Foo *self, int num)
>
> Cons:
> * One additional line of code per method for members lookup
> * One additional global variable access per method call for
>   members lookup

I concur with you that this is our best option.  I think it's the most sound
and straightforward construct/algorithm available to us.

It's frustrating that we have those global variable accesses for e.g.
`Foo_IVARS_OFFSET`, but at least it's possible to set that variable at
VTable-init time and forget about it.  What really sticks in my craw is that
it's the _ELF_ rules which force it to be looked up every last access, but
it's entirely possible that the lookup won't matter in practice.  We can
benchmark the result of setting all the IVARS_OFFSET variables to compile-time
constants if we want to find out how much we're paying.

For the record, I thought a little harder today about aliasing and concluded
that there's no way to turn off -fno-strict-aliasing even if `self` is allowed
to point at different places within an object.  Even if `A` does not point at
the exact same address as `B`, what matters is that it can still be alias for
_the same object_ -- so you have to be pessimistic about caching field values
in registers unless your compiler can do serious aliasing analysis and suss
out which variables can alias and which can't.

Another note: making the transition to members structs will be
straightforward, if a little tedious.

1.  #define `Foo_IVARS` as `Foo`
2.  Set Foo_GET_IVARS() to return `self`.
3.  Change over all struct access in the Lucy core to use IVARS.
4.  Change over Foo_IVARS to be only class-specific member variables.
5.  Stop providing struct defs for `Foo`.

Marvin Humphrey

Reply via email to