poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] A new mechanism to access the active field of unions


From: Mohammad-Reza Nabipoor
Subject: [RFC] A new mechanism to access the active field of unions
Date: Thu, 4 Mar 2021 23:02:38 +0330

Hello.

The current approach to deal with unions using exception is not elegant.

```poke
try u.field1 = 1;
catch if E_elem {};
```

These are my initial ideas regarding this problem:


=== Option 1. Overloading of `isa` operator

```poke
if (u isa TargetType) {
}
```

But overloading `isa` operator will change the current behavior:

```poke
type U1 =
  union
  {
    int i;
  };
var u1 = U1 {};

// current behavior
assert (u1 isa U);
assert (!(u1 isa int));
```

=== Option 2. A new operator (e.g., `holds`)

```poke
assert (u1 isa U);
assert (u1 holds int);
```

But there's an issue here, `union`s, almost always are not defined as a type.
Here is an example:

type ID3V2_Frame =
  struct
  {
    char[4] id : id[0] != 0;
    uint32 size;
    uint16 flags;
    union
    {
      union
      {
        char = 0;
        char[size-1] frame_data;
      } text : id[0] == 'T';
      char[size] frame_data;
    } u;
  };
var frm1 = ID3V2_Frame @ 0#B;

if (frm1.u holds typeof(frm1.u.text)) { /* a hypothetical `typeof` operator */
  /* ... */
} else if (frm1.u holds char[]) {
  /* ... */
}
```

So two new operators:
  - `holds`
  - `typeof`


=== Option 3. Adding more reflection (introspection) facilities to unions

```poke
if (frm.u'holds("text")) {
  /* ... */
} else if (frm.u'holds("frame_data")) {
  /* ... */
}

assert (frm.u'fields in ["text", "frame_data"]);
```

Now the challenge is how to access unnamed fields?
Maybe we don't need to!

Because of using strings, this approach is very flexible and powerful
but also error-prone; bugs can creep more easily (typo, change of field
name, ...).
(I think in situations like `(frm.u'holds("frame_data")` compiler actually
is capable of checking that `frm.u` has a field called "frame_data" at
compile-time. So it can solves most of the possible mistakes)


The user also can use the visitor pattern:
(I'm not 100% sure about using `holds` attribute on `any`)


```poke
type UVisitorFunc = (any)void;
type UVisitor =
  struct
  {
    string field;
    UVisitorFunc func;
  };
fun uvisit = (any u, UVisitor[] visitors) void:
  {
    for (f in u'fields)
      if (u'holds (f))
        for (v in visitors)
          if (v.field == f)
            {
              v.func (u);
              return;
            }
  }

uvisit (
  frm1,
  [
    UVisitor {
      name = "text",
      func = lambda (any u) void: { print "active field: text!\n"; },
    },
    UVisitor {
      name = "frame_data",
      func = lambda (any u) void: { print "active field: frame_data!\n"; },
    },
  ]);

```

If Poke had an associative array:

```poke
uvisit (
  frm1,
  {
    "text":       lambda (any u) void: { print "active field: text!\n"; },
    "frame_data": lambda (any u) void: { print "active field: frame_data!\n"; },
  });
```


More ideas?


Regards,
Mohammad-Reza


reply via email to

[Prev in Thread] Current Thread [Next in Thread]