On Tue, 17 Sep 2002, Leopold Toetsch wrote: > ... and the default.pmc will catch any abuse of adding a "Sub" to an int > and throw an exception.
Right. The current default.pmc non-error implementation of get_integer (returning cache.int_val) is wrong, and should go away. > > ... IMHO once a class > > says how it can be interpreted as e.g. a number, it's eminently reasonable > > to default the rest of its numeric operations, and to do widening > > conversions to take advantage of implemented ops. > > Yes of course. What once was in "default.pmc" will be "scalar.pmc", > where all scalar like classes can inherit from. And from which perlarray.pmc, perlhash.pmc, and (probably) a whole host of other types that need scalar-like operations will inherit. > > I guess one way to measure which way makes more sense is to put in the new > > default.pmc, then see if there end up being any classes inheriting from it > > directly, or if everything goes through an intermediate conversion class. > > As I already stated, we had til now _no_ inheritance from "default.pmc" > except for the famous "Subscript on something that's not an aggregate". And invoke for integers. > >>Then they should implement an empty init() function (Currently we don't > >>have this case AFAIK). > > > "Should not!" ;) > > This is one additional line. Please compare this with 5KB lines I saved > in array.pmc. Okay, but these two things are unrelated. We can save both the 5k in array.pmc _and_ the two lines in every single other class by having a default empty init. > Summary: > default.pmc catches errors, and may provide e.g. ->name or ->type. > scalar.pmc will be the default scalar base class. Why only (or even) ->name and ->type? Here's a list of what seems reasonable to me, default-wise. I suspect we agree more than it seems. You also might want to take a look at pdd02_vtables, which gives some indication of what should and should not throw exceptions. These will doubtless need some tweaking, but better to figure this out once now than to keep playing with it into the indefinite future, when a bunch of dependent classes may have to change along with it. /s For X_keyed_int(y) where X_keyed() exists, the default should be to call X_keyed(make_key(y)). When X_keyed() is the default/error implementation, doing so will throw an error. For X_keyed(k, y), call get_pmc_keyed(k)->X(y), e.g. elements_keyed(k) becomes get_pmc_keyed(k)->elements(). For X_keyed(k, y, value_key), call get_pmc_keyed(k)->X_keyed(rest_of_key, y, value_key). For set_X(PMC p) where set_X_native(n) exists, call set_X_native(p->get_X()) if it exists in non-default form. If not, call set_pmc(p), e.g. set_number(p) becomes either set_number_native(p->get_number()) or set_pmc(p), depending on what our derived class implements. Analogously, for set_X_same(PMC p), call set_X(p) if it is non-default, or set_same(p). For arithmetic op OP (add,subtract,multiply,divide,mod): - OP_int(v, res) -> res->set_integer_native(v OP SELF->get_integer()) - OP_number(v, res) -> res->set_number_native(v OP SELF->get_number()) - OP_bignum(v, res) -> res->set_bignum_native(bignum_OP(v, SELF->get_bignum()) - OP_same -> OP - OP(v, res) -> error - OP_keyed[_int] -> (see above) For bitwise op OP (or,and,xor,shl,shr,not): - OP_int(v, res) -> res->set_integer_native(v OP SELF->get_integer()) - OP_same -> OP - OP -> error void init() - do nothing (or call init_pmc(NULL)) void init_pmc(PMC* initializer) - do nothing void morph(INTVAL type) - error PMC* mark(PMC* tail) - nothing void destroy() - nothing INTVAL type() - return whatever type this has been enumerated to be INTVAL type_keyed(PMC* key) - error UINTVAL subtype(INTVAL type) - subtypes don't seem to be used now UINTVAL subtype_keyed(PMC* key, INTVAL type) - error STRING* name() - "return whoami"? STRING* name_keyed(PMC* key) - error PMC* clone() - memcpy PMC* clone_keyed(PMC* key) - error PMC* find_method(STRING* method_name) - error PMC* find_method_keyed(PMC* key, STRING* method_name) - error INTVAL get_integer() - error FLOATVAL get_number() - (FLOATVAL)get_integer(), or maybe an error if FLOATVALs lose precision when converting to INTVALs on this platform. BIGNUM* get_bignum() - make_bignum(get_{integer,number}()) -- depends which people prefer STRING* get_string() - error INTVAL get_bool() - error, unless everyone agrees on a common standard of truth w.r.t. get_string or get_integer. INTVAL elements() - error PMC* get_pmc() - return SELF, assuming very few classes will return something other than themselves. INTVAL is_same(PMC* value) - return value == SELF (i.e. same address) void set_integer_native(INTVAL value) - set_number_native((FLOATVAL)value), or set_bignum_native if loss of precision might result. void set_number_native(FLOATVAL value) - set_bignum(make_bignum(value)) void set_bignum_native(BIGNUM* value) - error void set_string_native(STRING* value) - error void set_pmc(PMC* value) - error void set_same(PMC* value) - set_pmc(value) void set_same_keyed(PMC* key, PMC* value, PMC* value_key) - get_pmc_keyed(key)->set_pmc_keyed(rest_of_key, value, value_key) INTVAL pop_integer() - (INTVAL)pop_float/pop_bignum, depending on width, if it is non-default. Otherwise, pop_pmc()->get_integer() FLOATVAL pop_float() - (FLOATVAL)pop_bignum() or pop_pmc->get_float(). This should be renamed to pop_number(). BIGNUM* pop_bignum() - pop_pmc->get_bignum() STRING* pop_string() - pop_pmc->get_string() PMC* pop_pmc() - error or splice void push_integer(INTVAL value) - push_number(value) void push_float(FLOATVAL value) - push_bignum(value) void push_bignum(BIGNUM* value) - error void push_string(STRING* value) - error void push_pmc(PMC* value) - error shift, unshift -- same as push/pop ## void splice ??? - would be nice... void neg(PMC* dest) - error (?) void concatenate(PMC* value, PMC* dest) - concatenate_native(value->get_string(), dest) void concatenate_native(STRING* value, PMC* dest) - dest->set_string_native(cat(SELF->get_string(), value)) void concatenate_same(PMC* value, PMC* dest) - concatenate() INTVAL is_equal(PMC* value) - if cmp is non-default, (cmp(value) == 0), otherwise is_same(). INTVAL cmp(PMC* value) - error INTVAL cmp_num(PMC* value) - numcmp(SELF->get_bignum(), value->get_bignum()) INTVAL cmp_string(PMC* value) - strcmp(SELF->get_string(), value->get_string()) NOTE: particularly for xor, but also for other things, we could use a set_boolean(PMC) and a set_boolean_native(INTVAL). void logical_or(PMC* value, PMC* dest) - if SELF->get_bool() dest->set_boolean(SELF) else dest->set_boolean(value) void logical_and(PMC* value, PMC* dest) - if !(SELF->get_bool()) dest->set_boolean(SELF) else dest->set_boolean(value) void logical_xor(PMC* value, PMC* dest) - dest->set_boolean_native(SELF->get_bool() xor value->get_bool()) void logical_not(PMC* dest) - dest->set_boolean_native(!SELF->get_bool()) void repeat(PMC* value, PMC* dest) - repeat_int(value->get_integer(), dest) void repeat_int(INTVAL value, PMC* dest) - error void increment() - SELF->set_same(SELF->add_integer(1, SELF)) void decrement() - SELF->set_same(SELF->subtract_integer(1, SELF)) INTVAL exists_keyed(PMC* key) - error INTVAL defined() - return 1 void delete_keyed(PMC* key) - error PMC* nextkey_keyed(PMC* key) - error void substr(INTVAL offset, INTVAL length, PMC* dest) - dest->set_string_native(substr_str(offset, length)) STRING* substr_str(INTVAL offset, INTVAL length) - substr(SELF->get_string(), offset, length) void* invoke(void* next) - error