[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
- [RFC] A new mechanism to access the active field of unions,
Mohammad-Reza Nabipoor <=
Re: [RFC] A new mechanism to access the active field of unions, Dan Čermák, 2021/03/05