FAQ

Design Team Issues: Numeric Types

Michael Lazzaro
Nov 18, 2002 at 7:20 pm
Here are some issues we need the design team to decide.

(A) How shall C-like primitive types be specified, e.g. for binding
to/from C library routines, etc?

Option 1: specify as property

my numeric $a is ctype("unsigned long int"); # standard C type
my numeric $b is ctype("my_int32"); # user-defined
my numeric $c is ctype("long double");

my int $a is range(1000..1255) is unchecked; # auto-infer 8bit

Option 2: specify as type

my u_long $a; # standard C type
my long_double $c;

Option 3: ???

(See p6d discussion, "Numeric Types")


(B) Need to know the root of the numeric types

Option 1:
numeric (mostly abstract base class)
- num
- int

Option 2:

num (floating point 'num' is the base class)
- int

Option 3: ???


(C) If C-like primitives are builtin, need to know what their type
names/aliases will be, and need to verify whether _ALL_ will have
promoted counterparts, e.g. numeric -> Numeric, u_long -> U_Long, etc.

# (TEMPORARY) need final list of numeric types & any aliased names,
# assuming we don't want to support *all* of these names (tho we could)

# the base numeric type

numeric

# signed integers

int
int8 char
int16 short short_int
int32 long long_int
int64 quad long_long long_long_int

# unsigned integers

bit
uint u_int
uint8 u_int8 u_char byte
uint16 u_int16 u_short u_short_int
uint32 u_int32 u_long u_long_int
uint64 u_int64 u_quad u_long_long u_long_long_int

# floating point numbers

num (== double)
float
double
long_double

MikeL
reply

Search Discussions

5 responses

  • Dave Whipp at Nov 18, 2002 at 9:33 pm
    "Michael Lazzaro" <mlazzaro@cognitivity.com> wrote
    (A) How shall C-like primitive types be specified, e.g. for binding
    to/from C library routines, etc?

    Option 1: specify as property

    my numeric $a is ctype("unsigned long int"); # standard C type
    my numeric $b is ctype("my_int32"); # user-defined
    my numeric $c is ctype("long double");

    my int $a is range(1000..1255) is unchecked; # auto-infer 8bit
    Just to clarify: I think of the latter (C<range>) for efficient
    packing into arrays (e.g. a 5-bit range can be packed efficiently,
    even though there is no 5-bit c-type): binding to C routines is
    probably best done explicity.

    The C<unchecked> property would enable performance
    optimizations. Checked-ranges probably catch a few more
    bugs, though.


    Dave.
  • Michael Lazzaro at Nov 18, 2002 at 11:30 pm

    On Monday, November 18, 2002, at 01:33 PM, Dave Whipp wrote:
    my int $a is range(1000..1255) is unchecked; # auto-infer 8bit
    Just to clarify: I think of the latter (C<range>) for efficient
    packing into arrays (e.g. a 5-bit range can be packed efficiently,
    even though there is no 5-bit c-type): binding to C routines is
    probably best done explicity.

    The C<unchecked> property would enable performance
    optimizations. Checked-ranges probably catch a few more
    bugs, though.
    Yeah, I threw that one in because it demonstrated a similar case of
    using properties to represent "hints" that could be optimized at a very
    primitive level, not because the last example itself necessarily
    represents an explicit C type. Sorry for the ambiguity there...

    MikeL
  • Larry Wall at Nov 19, 2002 at 12:54 am
    On Mon, Nov 18, 2002 at 11:22:00AM -0800, Michael Lazzaro wrote:
    : Here are some issues we need the design team to decide.

    I shall presume that I can speak for the design team. :-)

    : (A) How shall C-like primitive types be specified, e.g. for binding
    : to/from C library routines, etc?
    :
    : Option 1: specify as property
    :
    : my numeric $a is ctype("unsigned long int"); # standard C type
    : my numeric $b is ctype("my_int32"); # user-defined
    : my numeric $c is ctype("long double");
    :
    : my int $a is range(1000..1255) is unchecked; # auto-infer 8bit
    :
    : Option 2: specify as type
    :
    : my u_long $a; # standard C type
    : my long_double $c;
    :
    : Option 3: ???
    :
    : (See p6d discussion, "Numeric Types")

    These options are not mutually exclusive in the presence of type
    aliasing. However, my overall preference is to keep the base language
    clear of lots of type names, but allow you to add in any number of
    properties that constrain or clarify the basic types. There's no
    reason we couldn't say

    use ctypes;

    and get in all the short definitions, for some definition of "all".
    But I don't want to inflict all these names on ordinary Perl programmers.
    That would just be cruel.

    : (B) Need to know the root of the numeric types
    :
    : Option 1:
    : numeric (mostly abstract base class)
    : - num
    : - int
    :
    : Option 2:
    :
    : num (floating point 'num' is the base class)
    : - int
    :
    : Option 3: ???

    I'd lean towards option 1, insofar as low-level types can be considered
    objects at all. I suppose there might also be an abstract Numeric type...

    : (C) If C-like primitives are builtin, need to know what their type
    : names/aliases will be, and need to verify whether _ALL_ will have
    : promoted counterparts, e.g. numeric -> Numeric, u_long -> U_Long, etc.

    This seems like trying to count how many species of mammal have wings.
    You can't have a type that is simultaneously constrained and not
    constrained to fit within a certain representation specification.

    : # (TEMPORARY) need final list of numeric types & any aliased names,
    : # assuming we don't want to support *all* of these names (tho we could)
    :
    : # the base numeric type
    :
    : numeric
    :
    : # signed integers
    :
    : int
    : int8 char
    : int16 short short_int
    : int32 long long_int
    : int64 quad long_long long_long_int

    Are these actual sizes, or minimal sizes? If you ask for int8, is
    the implemenation allowed to stick it into an int16?

    : # unsigned integers
    :
    : bit
    : uint u_int
    : uint8 u_int8 u_char byte
    : uint16 u_int16 u_short u_short_int
    : uint32 u_int32 u_long u_long_int
    : uint64 u_int64 u_quad u_long_long u_long_long_int
    :
    : # floating point numbers
    :
    : num (== double)
    : float
    : double
    : long_double

    I'd say generating this list is the job of whoever writes the ctype
    module. And that's a bit of a crock anyway, since the available types
    will really depend on the underlying C/Java/C#/whatever implemenation.

    Larry
  • Michael Lazzaro at Nov 19, 2002 at 10:36 pm

    On Monday, November 18, 2002, at 04:54 PM, Larry Wall wrote:
    : (B) Need to know the root of the numeric types
    :
    : Option 1:
    : numeric (mostly abstract base class)
    : - num
    : - int
    :
    : Option 2:
    :
    : num (floating point 'num' is the base class)
    : - int

    I'd lean towards option 1, insofar as low-level types can be considered
    objects at all. I suppose there might also be an abstract Numeric
    type...
    .... IIR, Damian previously recommended option 2. Do you want to fight
    it out with him, or overrule? :-)

    If it isn't obvious to everyone else, the main (only?) reason to care
    about this is when checking/specifying context/args. Assume num means
    a double-precision float.

    Simply put: (a) if you pass an <int> to a function defined as taking a
    (floating-point) <num>, does the function always convert your <int> to
    a <num> before doing anything with it, or does it know it doesn't have
    to? And (b) are you allowed to discriminate between 'floating point'
    and 'integer' context, and how?

    Option 1:

    sub foo(num $n; int $i) # _always_ forces $n to a double
    # _always_ forces $i to an int
    sub bar(numeric $n) # allows both int or double, doesn't care

    if want numeric {
    if want int { ... } # both are subclasses of numeric,
    if want num { ... } # but only siblings to each other
    }

    Option 2:

    sub foo(num $n; int $i) # allows $n as int or double
    # $i always forced to an int
    sub bar(num $n) # allows both int or double, doesn't care

    if want numeric { # (maybe still want abstract base anyway)
    if want num { # num is the base class
    if want int { ... } # int is special case of a num
    }
    }

    .... Nasty issue. #1 allows you to be more precise, important if
    constantly converting nums <--> ints would notably slow things. But #2
    more obviously does WYM most of the time.

    Hmm, here might be an answer (thinking aloud). Perhaps <num> is the
    base class, just like it is now (you can put both floats and integers
    in it, it doesn't care). <int> is for explicit integer, <float> is for
    explicit double.

    num
    - int
    - float

    Such that the literal 1.234 is born as type <float>, which is trivially
    type <num>. Literal 1234 is treated as an <int>, same deal.

    So we'd still use <num> and <int> for most things, but we'd have
    <float> hanging out as a way to explicitly type/cast/contextify*:

    sub foo(float $i)

    .... in cases where it really mattered. Would that better solve the
    issues in options 1 and 2(?)

    MikeL

    *(contextify? contextification?) :-)
  • Allison Randal at Nov 20, 2002 at 6:24 pm

    Mike wrote:
    : (B) Need to know the root of the numeric types
    If it isn't obvious to everyone else, the main (only?) reason to care
    about this is when checking/specifying context/args. Assume num means
    a double-precision float.

    Simply put: (a) if you pass an <int> to a function defined as taking a
    (floating-point) <num>, does the function always convert your <int> to
    a <num> before doing anything with it, or does it know it doesn't have
    to? And (b) are you allowed to discriminate between 'floating point'
    and 'integer' context, and how?

    Option 1:

    sub foo(num $n; int $i) # _always_ forces $n to a double
    # _always_ forces $i to an int
    sub bar(numeric $n) # allows both int or double, doesn't care

    if want numeric {
    if want int { ... } # both are subclasses of numeric,
    if want num { ... } # but only siblings to each other
    }

    Option 2:

    sub foo(num $n; int $i) # allows $n as int or double
    # $i always forced to an int
    sub bar(num $n) # allows both int or double, doesn't care

    if want numeric { # (maybe still want abstract base anyway)
    if want num { # num is the base class
    if want int { ... } # int is special case of a num
    }
    }

    .... Nasty issue. #1 allows you to be more precise, important if
    constantly converting nums <--> ints would notably slow things. But #2
    more obviously does WYM most of the time.

    Hmm, here might be an answer (thinking aloud). Perhaps <num> is the
    base class, just like it is now (you can put both floats and integers
    in it, it doesn't care). <int> is for explicit integer, <float> is for
    explicit double.

    num
    - int
    - float

    Such that the literal 1.234 is born as type <float>, which is trivially
    type <num>. Literal 1234 is treated as an <int>, same deal.

    So we'd still use <num> and <int> for most things, but we'd have
    <float> hanging out as a way to explicitly type/cast/contextify*:

    sub foo(float $i)

    .... in cases where it really mattered. Would that better solve the
    issues in options 1 and 2(?)

    MikeL

    *(contextify? contextification?) :-)
    A common base class is not necessary for automatic type casting.
    Besides, in p6, multimethod dispatch will be the preferred way of
    handling such cases.

    The p6 type system is still in heavy flux at the moment. There won't be
    any final answer until closer to A12. Go with what you have for now.
    Type casting isn't really a subject for first few chapters anyway.

    Allison

Related Discussions

Discussion Navigation
viewthread | post