Page 1 of 1

"... object must have mp_obj_base_t" - what about mp_obj_namedtuple_type_t

Posted: Mon Mar 26, 2018 9:34 pm
by jickster
I've been creating types and I've followed this rule

Code: Select all

// This mp_obj_type_t struct is a concrete MicroPython object which holds info
// about a type.  See below for actual definition of the struct.
typedef struct _mp_obj_type_t mp_obj_type_t;

// Anything that wants to be a concrete MicroPython object must have mp_obj_base_t
// as its first member (small ints, qstr objs and inline floats are not concrete).
struct _mp_obj_base_t {
    const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT;
};
typedef struct _mp_obj_base_t mp_obj_base_t;
// Anything that wants to be a concrete MicroPython object must have mp_obj_base_t
// as its first member (small ints, qstr objs and inline floats are not concrete).


and everything has worked out.

So then why are there native types that do not follow this rule?

Code: Select all

#if MICROPY_PY_COLLECTIONS

typedef struct _mp_obj_namedtuple_type_t {
    mp_obj_type_t base;
    size_t n_fields;
    qstr fields[];
} mp_obj_namedtuple_type_t;
I understand that the only difference between

Code: Select all

mp_obj_type_t 
and

Code: Select all

mp_obj_base_t 
is that

Code: Select all

mp_obj_base_t 
is a struct containing a

Code: Select all

mp_obj_type_t *
.

So why is it ok to use mp_obj_type_t directly?

Re: "... object must have mp_obj_base_t" - what about mp_obj_namedtuple_type_t

Posted: Mon Mar 26, 2018 9:42 pm
by dhylands
I'm going to guess that it's just an oversight, and that it really should be an mp_obj_base_t.

The reason it happens to work is because mp_obj_base_t and mp_obj_type_t are both the same size.

mp_obj_base_t includes an alignment directive that the namedtuple is lacking, so declaring a static namedtuple might be problematic on say a 16-bit architecture like the pic16bit port.

Re: "... object must have mp_obj_base_t" - what about mp_obj_namedtuple_type_t

Posted: Tue Mar 27, 2018 2:11 pm
by jickster
dhylands wrote:
Mon Mar 26, 2018 9:42 pm
I'm going to guess that it's just an oversight, and that it really should be an mp_obj_base_t.

The reason it happens to work is because mp_obj_base_t and mp_obj_type_t are both the same size.

mp_obj_base_t includes an alignment directive that the namedtuple is lacking, so declaring a static namedtuple might be problematic on say a 16-bit architecture like the pic16bit port.
They're not the same size. Nowhere near.

mp_obj_type_t is a struct containing many elements

Code: Select all

typedef struct _mp_obj_type_t mp_obj_type_t;

struct _mp_obj_type_t {
    // A type is an object so must start with this entry, which points to mp_type_type.
    mp_obj_base_t base;

    // The name of this type.
    qstr name;

    // Corresponds to __repr__ and __str__ special methods.
    mp_print_fun_t print;
...
mp_obj_base_t is a struct containing one item: a pointer to mp_obj_type_t

Code: Select all

struct _mp_obj_base_t {
    const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT;
};
typedef struct _mp_obj_base_t mp_obj_base_t;

Re: "... object must have mp_obj_base_t" - what about mp_obj_namedtuple_type_t

Posted: Tue Mar 27, 2018 3:47 pm
by dhylands
My bad. I wasn't looking at the right thing.

The named tuple type has an mp_obj_type_t as its first member, and mp_obj_type_t has the base type as its first member, so the first 4 bytes of a named tuple is still a pointer to the base type.

I'd have to look at a bunch more of the code to see why it was done this way instead of the way the other native types were done.