No struct extending?

Steve Horne stephenwantshornenospam100 at aol.com
Sat Sep 9 03:21:52 PDT 2006


On Fri, 08 Sep 2006 20:20:29 +0100, Stewart Gordon
<smjg_1998 at yahoo.com> wrote:

>Steve Horne wrote:
>> In C++, 'struct' is (almost) a synonym for 'class'. More a declaration
>> of intent than a different thing. One useful side-effect of this is
>> that you can declare structs as extensions of other structs. This can
>> be useful even for plain-old-data. e.g. data structures with several
>> node types, but some shared fields. Inheritance doesn't always imply
>> virtual tables and stuff.
>
>I can imagine that such a feature could be useful indeed.  However, the 
>approach you propose has a caveat.
>
>The problem is that the extending concepts currently in D - class 
>inheritance, interface implementation and enum base types - satisfy the 
>"is a" relationship.  Basically, given

branch_node isa node
leaf_node   isa node

The common part only represents what is associated with node-ness, as
opposed to specifically branch-nodeness or leaf-nodeness.


>     class Qwert : Yuiop

>you can keep any Qwert in a variable of type Yuiop

Not quite. You can reference any Qwert from a variable of type Yuiop.
That implicit reference is important. Convert the instance itself and
you lose data.

And the kinds of run-time type resolution or binding are exactly the
same as for nodes. I have to check before downcasting a pointer. You
have to check before downcasting a reference. You just have some
built-in compiler support, of course - I'm just working in the
abstract sense of a heirarchy or classes, as opposed to the specific
sense supported by this language.

Branch-node isa node. Why shouldn't that relationship be known to the
compiler?

It's not just C++ oriented thinking. It's a wider issue, in principle.
Call it database-style object orientation. An object oriented database
basically provides heirarchies of related record structures, after
all.

>In a union?  Doesn't seem to make sense.

I'm saying that every time I access a field, I have to specify a
qualifier for each layer...

  pointer.m_Branch.m_Field

instead of...

  pointer.m_Field

Nothing profound or anything - just saying that while anonymous unions
can be used to get variants without needing extra qualifiers, it
doesn't help in this case.

>But an idea would be to have a means whereby a defined struct can be 
>used as an anonymous struct.  It would also be handy if a struct 
>instance could be both anonymous and named, if you know what I mean.

Kind of. Like using 'mixin' with a struct as the source instead of a
template. Could be handy.

But in the cases I have in mind, that's just a minor shorthand to one
of the options I described anyway - mixin the base struct itself,
rather than defining a separate template and mixing that into all
structs. It doesn't tell the compiler anything new about my intent. In
itself.

>But you remind me of an idea I've had for a while, which is being able 
>to derive a union from a union or struct.  This would be used to wrap a 
>structure from an external API and give it methods or alternative views 
>of the data.

Maybe.



Actually, scratch all the inheritance stuff. It's just a special case
of another requirement anyway, with structs. Aligning members. Not in
the 'alignof' sense, but in terms of field positioning.

Perhaps if I could write...

  struct s_Branch
  {
    at 0: s_Common m_Common;
  }

Still have the dotted qualifiers to deal with, but that's just a minor
irritation. The point is that the qualifier has this declaration of
intent - where the embedded field should be.

And then of course...

  struct s_Branch
  {
    at 0: mixin (s_Common);  //  s_Common being a struct
  }

Now we're getting somewhere!

Each 'at' clause would be a signal to either add whatever padding to
the struct is needed, or to report an error if that offset has already
been passed.

Could be useful for general file/protocol layout stuff anyway. It can
be easy to mess up with 'align', for instance. Especially if the
default align size platform dependent?


And then, how about something like...

  group (x, y)
  {
    struct s_Block_1
    {
      at x : int32_t  m_1;
             int32_t  m_2;             
      at y : float    m_3;
    }

    struct s_Block_2
    {
      at x : int32_t  m_1;
             float    m_2;
      at y : float    m_3;
    }
  }

That is, the (presumably in-memory-only) structs have common parts
which must be at the same offset in each struct, but not specifying an
exact location. Each 'at' offset would be set to the minimum value
possible given the field sizes and alignment. And there'd be no
possibility of packing later fields into earlier gaps, on the
principle of least surprise.

Another approach might be same-field-name-implies-same-offset within a
group of structs.

This is, of couse, in the field of obscure requirements and long-term
possible futures. But an explicit field position sounds more
immediately useful.

-- 
Remove 'wants' and 'nospam' from e-mail.



More information about the Digitalmars-d mailing list