Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[SUMMARY] Typed vs. Untyped: what "my $x" means

18 views
Skip to first unread message

Michael Lazzaro

unread,
Apr 18, 2003, 3:07:29 PM4/18/03
to perl6-l...@perl.org
OK, let's start over, if we can. Forget the object stuff, forget the
A12 stuff, forget the automatic coercions from one type to another.
Let's just take the simplest possible cases re A2, A3.

So some explanations, based on what we know. Forgive me where I use
dumb words like "thing" -- I want to avoid loaded terms wherever
possible. I am trying to describe HOW IT ACTS, not WHY IT ACTS THAT
WAY. The farther down you go, the more the assertions stack on one
another, and the more likely it is that I've screwed something up.

NOTE -- I am using two terms, here -- C<ScalarC> and C<Scalar> to mean
"the container class named Scalar" and "the value type named Scalar",
respectively. I don't know if they are both named C<Scalar>, or only
one is. This, I think, is the source of most of our confusion.


[1. Variables]

There are three basic "types" of variables:

[1.1] A scalar variable, $v, may hold one atomic thing, like an
integer, a string, or a reference.

[1.2] An array variable, @v, may hold an ordered list of scalar things,
accessed by (integer) position.

[1.3] A hash variable, %v, may hold an unordered set of scalar things,
accessed by (scalar) key.

All variables are derived from one of these three "base" variable types.


[2. Associating Variables with Types]

[2.1] The statement:

my $i;

declares a new variable, named $i, that may store a value of any scalar
type. By way of definition, we will call this an "untyped" scalar
variable. By "untyped", we mean that no particular type will be
enforced -- any scalar type may be placed in an "untyped" variable, and
may be retrieved w/out casting of any sort.

The following stores (by reference) a newly created object of class
C<Foo>.

my $i;
$i = Foo.new;
ref($i); # returns C<Foo>


[2.2] These statements:

my $i;
my $i is ScalarC;

are equivalent. C<ScalarC> is the default container class for scalar
variables, one which, by default, enforces no particular type on the
values the variable may contain.


[2.3] The statements:

my Int $i;
my $i is ScalarC of Int;

both declare that the variable $i may only hold values of type C<Int>,
or values derived from type C<Int>, or values of a type with the same
interface as C<Int>.


[2.4] Note that you may not subclass the more efficient "primitive"
types such as C<int> or C<str>, but you _can_ subclass C<Int> or C<Str>.

class MyInt is int; # COMPILETIME ERROR: use 'Int', not 'int'
class MyInt is Int; # OK


[2.5] The statement:

my $i is Foo;

declares that the variable $i is implemented by the class C<Foo> --
that is, that the container itself is implemented by a C<Foo> object,
which is expected to implement the same interfaces as the default
container class, C<ScalarC>. This is how C<tie> behavior will
typically be implemented in Perl6. C<$i> remains an "untyped"
variable, which may store values of any scalar type.


[2.6] The statements:

my Int $i is Foo;
my $i is Foo of Int;
my $i is Foo returns Int;

are synonymous, and declare that the variable is implemented by class
C<Foo>, and will store only values of type C<Int>.


[2.7] It is possible to declare "container" implementations that
enforce type on the contained value. The statements:

class FooInt is Foo of Int {...}

my $i is FooInt;

will produce a variable $i identical to those in [2.6].


[3. Literal Values]

[3.1] Literal scalar values are ALWAYS of type C<Scalar>. The type
C<Scalar> is a junction of all other scalar types, e.g.
int|Int|str|Str|Ref|Code|etc.

ref( 1 ); # returns Scalar;
ref( '1' ); # returns Scalar;

Though they may look the part, literals are never of type int, str,
Int, Str, etc, however they may easily be transformed into those other
types.

There is no such thing as an "untyped" value. All values have types,
even if that type is merely the root junctive, C<Scalar>.


[3.2] The statement:

my $i = 1;

stores the C<Scalar> C<1> into the C<Scalar>-typed variable C<$i>, such
that

ref( $i );

returns C<Scalar>.


[3.3] In the code:

my Int $i;
$i = 1;

the literal value C<1> is of type C<Scalar>, NOT of type C<Int>. When
the C<Scalar> value C<1> is placed into the C<Int>-typed variable $i,
the resulting value is of type C<Int>. Specifically, the action:

$i.STORE( 1 );

places the C<Int> value of the literal Scalar C<1> into $i, discarding
other aspects of the value, such that

ref( $i );

returns C<Int>.


[3.4] The above behavior is called the "casting" of a Scalar type to an
Int type. [mjl- or the "coercion"? No, I think we need that word to
mean something different]


[3.5] The behavior of the junction type C<Scalar> is such that the
following are always true:

my Int $x = 123; # stores Int-typed 123
my Int $x = "123"; # stores Int-typed 123
my Str $x = 123; # stores Str-typed "123"
my Str $x = "123"; # stores Str-typed "123"

This allows literal numeric and string values to be used
interchangeably.


[4. Strong Typing]

[4.1] Declaring a "type" for a variable enforces that the variable may
store _only_ values of that class or type, or that are derived from
that class or type.

my Int $i;
$i = 1; # OK

class MyInt is Int;
$i = MyInt.new; # also OK


[4.2] [mjl-- does there need to be a differentiation between "may store
this class or any subclass" and "may store only this class, and _not_
subclasses?"]


[4.3] Attempting to store a typed value of a type other than the type
specified is a compiletime error.

class Foo;
class Bar;

my Foo $f;
$f = Bar.new; # COMPILETIME ERR

my Bar $b;
$f = $b; # COMPILETIME ERR


[4.4] Strongly typed variables may store subclasses of the declared
class, but not superclasses of that class.

class FooA {...};
class FooB is FooA {...};
class FooC is FooB {...};

my FooB $f;
$f = FooB.new; # OK
$f = FooC.new; # OK
$f = FooA.new; # COMPILETIME ERROR

This is because a FooC is minimally known to inherit the interface of
FooB, but FooA is _not_ known to conform to that particular interface.

(Note that the above can be a compiletime error because the constructor
method of each class is known to C<returns> the appropriate class, e.g.
the constructor methods are also strongly typed.)


[4.5] Assuming that Perl6 allows either "interfaces" or "multiple
inheritance", all interfaces or parent classes may participate.

class Foo is Bar is Baz;
my Foo $x = Foo.new; # OK
my Baz $x = Foo.new; # OK
my Bar $x = Foo.new; # OK

[mjl -- really? Hmm...]


[4.6] C<Int>, C<Str>, and other builtin types other than C<Scalar> do
not automatically coerce between each other; this, therefore, is an
error:

my Str $s;
my Int $i;

$i = $s; # COMPILETIME ERROR

If you want to coerce between two strongly typed vars, you must do so
via an explicit coercion. [mjl-- coercion syntax unknown]


[5. Interaction between Typed and Untyped Variables]

[5.1] In the following code:

my $x;

C<$x> is an "untyped" variable; that is, a variable which may store any
scalar type.


[5.2] In the code:

my $x = 1;

C<$x> now contains the C<Scalar>-typed value C<1>.


[5.3] In the code:

my $x = Int.new(1);

C<$x> now contains the C<Int>-typed value C<1>.


[5.4] In the code:

my Int $i = 1;
my $x = $i;

C<$x> now contains the C<Int>-typed value C<1>.


[5.5] In the code:

my $x = 1;
my Int $i = $x;
my Str $s = $x;

C<$i> contains the C<Int>-typed value C<1>, as obtained from the
C<Scalar>-typed value C<1> stored in C<$x>.

Likewise, C<$s> contains the C<Str>-typed value C<1>, as obtained from
the C<Scalar>-typed value C<1> stored in C<$x>.


[5.6] Assigning to an "untyped" var from a "typed" var is never an
error.

my Int $i;
my $x = $i;

This is because "untyped" vars are defined as being able to store any
possible scalar type.


[5.7] Assigning to a typed var from an "untyped" var may result in
deferring of typechecks until runtime, at which point an error may be
thrown if the type of the value is not compatible.

my Int $i = $x; # RUNTIME TYPECHECKING

(It is possible that, if the compiler can infer type through dataflow
analysis, the runtime typecheck may be optimized away.)


[5.8] In the code:

my Int $i = 1;
my $j = 1;
my $x;
my Str $s;

$x = $j; # OK; $x stores C<Scalar>-typed value C<1>
$x = $i; # OK; $x stores C<Int>-typed value C<1>

$s = $j; # OK; $s stores C<Str>-typed value C<1>
$s = $i; # COMPILE ERR; can't store C<Int> in C<Str>-typed var $s.
$s = $x; # RUNTIME ERR; can't store C<Int> in C<Str>-typed var $s.

The last line demonstrates that an "untyped" value does not _coerce_
values to C<Scalar> type, but merely allows any scalar type to be
placed and fetched, unaltered. If you want to coerce it, you must
explicitly do so yourself. [mjl-- coercion syntax unknown]

---

OK. What of that, so far, is not accurate?

MikeL

Austin Hastings

unread,
Apr 18, 2003, 3:42:00 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:

> OK. What of that, so far, is not accurate?

Very impressive, and it agrees with a lot of the stuff I remember
talking about and/or believing.

But which parts are speculation by us, and which parts are supported by
emissions from @Larry?

=Austin


Michael Lazzaro

unread,
Apr 18, 2003, 4:10:33 PM4/18/03
to Austin_...@yahoo.com, perl6-l...@perl.org

On Friday, April 18, 2003, at 12:42 PM, Austin Hastings wrote:
> Very impressive, and it agrees with a lot of the stuff I remember
> talking about and/or believing.
>
> But which parts are speculation by us, and which parts are supported by
> emissions from @Larry?

Other than my forced distinction between C<ScalarC> and C<Scalar>, I
*believe* all of what I wrote is grounded in previous emissions. It's
only when we go beyond it, to things like auto-coercions, explicit
coercions, etc., that we're getting speculative.

I do have some additional questions, based on that summary, but I
figure we should first see if anyone has any objections to what's there
right now... esp. the design team.

And we need clarification on whether the imaginary "ScalarC/Scalar"
distinction exists, or if the same word is indeed used for both
concepts -- and if so, how that's pulled off.

MikeL

Paul

unread,
Apr 18, 2003, 5:07:14 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org

off-list: feel free to post responses if you think there's value, but I
don't think I said anything much here that adds enough value to spam
everyone with it. I reply to you just in case something here actually
helps you clarify your thinking or phrasing.

Good job, and that you for it.

> NOTE -- I am using two terms, here -- C<ScalarC> and C<Scalar> to
> mean "the container class named Scalar" and "the value type named
> Scalar", respectively. I don't know if they are both named
> C<Scalar>, or only one is. This, I think, is the source of most
> of our confusion.

Is there ever a case where you'll need to type something as Scalar that
isn't a ref to such a value?

I suppose someone might subclass Scalar, but that's then not a Scalar
type. It's a subclass.

> [1. Variables]
> There are three basic "types" of variables:
> [1.1] A scalar variable, $v, may hold one atomic thing, like an
> integer, a string, or a reference.
> [1.2] An array variable, @v, may hold an ordered list of scalar
> things, accessed by (integer) position.
> [1.3] A hash variable, %v, may hold an unordered set of scalar
> things, accessed by (scalar) key.
> All variables are derived from one of these three "base" variable
> types.

Agreed. Can a hash key be a non-string now?
Could the key itself be a valid and usable object?


> [2.2] These statements:
>
> my $i;
> my $i is ScalarC;
>
> are equivalent. C<ScalarC> is the default container class for scalar
> variables, one which, by default, enforces no particular type on the
> values the variable may contain.

Therefore the second is redundant, unless as someone suggested it is
intended as a container to imply an implicit reference context. A12
again. ~sigh~

> [2.5] The statement:
>
> my $i is Foo;
>
> declares that the variable $i is implemented by the class C<Foo> --
> that is, that the container itself is implemented by a C<Foo> object,
> which is expected to implement the same interfaces as the default
> container class, C<ScalarC>. This is how C<tie> behavior will
> typically be implemented in Perl6. C<$i> remains an "untyped"
> variable, which may store values of any scalar type.

This could use some clarification, but I think I get it. You're
thinking in interface terms. Foo must be able to do what $i is likely
to be required to do, but can implement the methods to do .STORE,
.FETCH, .toString, etc.

> [3. Literal Values]
>
> [3.1] Literal scalar values are ALWAYS of type C<Scalar>. The type
> C<Scalar> is a junction of all other scalar types, e.g.
> int|Int|str|Str|Ref|Code|etc.
>
> ref( 1 ); # returns Scalar;
> ref( '1' ); # returns Scalar;

Ok, that took me a minute, but it can't include Array and Hash in that
juncture, can it? Those are collections, scalars are not. It most
certainly *does* include Refs to those types, however.



> Though they may look the part, literals are never of type int, str,
> Int, Str, etc, however they may easily be transformed into those
> other types.

That is a little harder to digest, but types are an artifact of context
and expectation, so 5 - "abc" could be construed as 5, because the
compiler would theoretically coerce "abc" to it's numeric equivelent,
zero. Am I following correctly?

> There is no such thing as an "untyped" value. All values have types,
> even if that type is merely the root junctive, C<Scalar>.

~frown~
So a literal 1 has no type until you use it, but when you do that it
becomes a value that must be typed; context is evaluated and the
resulting value is of the desired type? A nonliteral, on the other
hand, is *already* typed, so cross-assignment can be tested for
correct-ness.
I agree with the statement you've made, but elaboration hurts me.

> [3.2] The statement:
>
> my $i = 1;
>
> stores the C<Scalar> C<1> into the C<Scalar>-typed variable C<$i>,
> such that
>
> ref( $i );
>
> returns C<Scalar>.
>
>
> [3.3] In the code:
>
> my Int $i;
> $i = 1;
>
> the literal value C<1> is of type C<Scalar>, NOT of type C<Int>.
> When the C<Scalar> value C<1> is placed into the C<Int>-typed
> variable $i, the resulting value is of type C<Int>. Specifically,
> the action:
>
> $i.STORE( 1 );
>
> places the C<Int> value of the literal Scalar C<1> into $i,
> discarding other aspects of the value, such that
>
> ref( $i );
>
> returns C<Int>.

Sounds like handwaving.
Sounds like *correct* handwaving, though.

> [3.4] The above behavior is called the "casting" of a Scalar type
> to an Int type. [mjl- or the "coercion"? No, I think we need that
> word to mean something different]
>
> [3.5] The behavior of the junction type C<Scalar> is such that the
> following are always true:
>
> my Int $x = 123; # stores Int-typed 123
> my Int $x = "123"; # stores Int-typed 123
> my Str $x = 123; # stores Str-typed "123"
> my Str $x = "123"; # stores Str-typed "123"
>
> This allows literal numeric and string values to be used
> interchangeably.

Ok, maybe, since "123" is a literal, given the premise above.
We're obviously into hypothetica now, though.

> [4. Strong Typing]

This all looks good.

__________________________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo
http://search.yahoo.com

Paul

unread,
Apr 18, 2003, 5:08:40 PM4/18/03
to perl6-l...@perl.org

--- Paul <ydb...@yahoo.com> wrote:
> off-list: feel free to post responses if you think there's value, but
> I don't think I said anything much here that adds enough value to
spam
> everyone with it. I reply to you just in case something here actually
> helps you clarify your thinking or phrasing.

Sigh -- well, I *meant* to post it off-list.
Guess I've just gotten into the habit of hitting Reply-All.
Sorry, list.

Paul

Me

unread,
Apr 18, 2003, 5:22:08 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org
> [2.3] The statements:
>
> my Int $i;
> my $i is ScalarC of Int;
>
> both declare that the variable $i may only hold values of type C<Int>,
> or values derived from type C<Int>

Right.

> or values of a type with the same interface as C<Int>.

1. As Luke proposed, this could be inferred rather than
explicit, ie if a value can be an Int (based on its sigs
etc.) then it is an Int. It doesn't need to explicitly
say that it implements Int.

2. It might be that perl supports type checking in both
explicit (lyskov style type hierarchy compatibility or
explicit interface implements compatibility) or implicit
(inferred interface compatibility) ways. If so, it might
be that distinct syntax is required when specifying a
(value) type. As in (NOT REAL SYNTAX):

my $i is ScalarC of Int; # explicitly requires either
# an Int or derivative or
# thing that explicitly
# "implements Int"

my $i is ScalarC can Int;# explicitly requires a thing
# that can be an Int, as
# determined by analysis

The actual syntax will need to be something else because
it needs to work with C<returns> and just putting the
type before the variable name.


> [2.7] It is possible to declare "container" implementations that
> enforce type on the contained value. The statements:
>
> class FooInt is Foo of Int {...}
>
> my $i is FooInt;
>
> will produce a variable $i identical to those in [2.6].

I was thinking that the class declaration could say
either (NOT REAL SYNTAX) C<of> or C<can>, and could
specify a junction.

And one could then specify the value type to be a
subset of the container specified set:

class FooBB is Foo of Bar|Baz {...}

my Baz $i is FooBB;


> [4.3] Attempting to store a typed value of a type other than the type
> specified is a compiletime error.

> ...


> [4.4] Strongly typed variables may store subclasses of the declared
> class, but not superclasses of that class.

> ...


> [4.5] Assuming that Perl6 allows either "interfaces" or "multiple
> inheritance", all interfaces or parent classes may participate.
>
> class Foo is Bar is Baz;
> my Foo $x = Foo.new; # OK
> my Baz $x = Foo.new; # OK
> my Bar $x = Foo.new; # OK
>
> [mjl -- really? Hmm...]

This stuff is different if inferred types are involved.


All the rest made sense to me.

--
ralph

Me

unread,
Apr 18, 2003, 5:25:46 PM4/18/03
to Austin_...@yahoo.com, Michael Lazzaro, perl6-l...@perl.org
> Other than my forced distinction between C<ScalarC> and C<Scalar>

Perhaps paint that s/Scalar/Value/ and s/ScalarC/Scalar/.

--
ralph

John Williams

unread,
Apr 18, 2003, 5:34:22 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org
Excellent stuff generally, but (appologies in advance) this Section 3 just
doesn't work for me. I'm mostly going to present how I think about it as
an alternate point-of-view, in order to try not to be negative.

I'm willing to agree to disagree while we wait for the design team.

> [3. Literal Values]
>
> [3.1] Literal scalar values are ALWAYS of type C<Scalar>. The type
> C<Scalar> is a junction of all other scalar types, e.g.
> int|Int|str|Str|Ref|Code|etc.
>
> ref( 1 ); # returns Scalar;
> ref( '1' ); # returns Scalar;
>
> Though they may look the part, literals are never of type int, str,
> Int, Str, etc, however they may easily be transformed into those other
> types.
>
> There is no such thing as an "untyped" value. All values have types,
> even if that type is merely the root junctive, C<Scalar>.

It seems like you are setting up Scalar as a grand-unifying Junction
instead of a grand-unifying base class, and the Junction definition is
even worse.

Alternate POV: Each literal value has a specific type given to it by the
compiler. 1 is an Int (or maybe int), "2" is a Str, 3=>4 is a Pair, [5,6]
is an Array, etc. It looks like an Int, so it's an Int.

> [3.2] The statement:
>
> my $i = 1;
>
> stores the C<Scalar> C<1> into the C<Scalar>-typed variable C<$i>, such
> that
>
> ref( $i );
>
> returns C<Scalar>.

Alternate POV:

my $i;

creates a variable with a Scalar(P) variable type, but with no particular
value type (it's of/returns trait is undefined). Thus it can be
considered an "untyped" variable.

It's value type changes with the value. In this example the current value
type is, well, whatever the type of undef is. And undef's type is
probably not Scalar, since %h and @a can also be undef.

> [3.3] In the code:
>
> my Int $i;
> $i = 1;
>
> the literal value C<1> is of type C<Scalar>, NOT of type C<Int>. When
> the C<Scalar> value C<1> is placed into the C<Int>-typed variable $i,
> the resulting value is of type C<Int>. Specifically, the action:
>
> $i.STORE( 1 );
>
> places the C<Int> value of the literal Scalar C<1> into $i, discarding
> other aspects of the value, such that
>
> ref( $i );
>
> returns C<Int>.

Alternate POV:

The literal value C<1> is of type C<Int> (or C<int>). It is still Int
whether it is stored in a my $i or a my Int $i.

Just like the type of Foo.new is Foo, whether it is stored in a my Foo $f
or a my SuperClassOfFoo $f.

> [3.4] The above behavior is called the "casting" of a Scalar type to an
> Int type. [mjl- or the "coercion"? No, I think we need that word to
> mean something different]

Strong agreement here. The distinction that coersion or conversion is
different from the compiler-hint type of typecasting is too important to
be in a footnote.

> [3.5] The behavior of the junction type C<Scalar> is such that the
> following are always true:
>
> my Int $x = 123; # stores Int-typed 123
> my Int $x = "123"; # stores Int-typed 123
> my Str $x = 123; # stores Str-typed "123"
> my Str $x = "123"; # stores Str-typed "123"
>
> This allows literal numeric and string values to be used
> interchangeably.

I'm avoiding the conversion/coersion thread. But I will express my
opinion that type conversion has very little, if anything, to do with
inheritance, and that context plays a very major role.

Well, I guess I'm being sucked into it some anyway, to address the things
I object to in this section.

Alternate POV:

my Str $x = 123;

C<123> is of type C<Int>, because that is the type the compiler gave it
when it created that value in the compiled code. (You wrote it as an int,
so it stored in the bit pattern 0x7B probably.) Assuming the assignment is
legal (and I do make that assumption), the value 123 must be converted to
an Str before it is allowed into $x. The conversion process, of
necessity, creates a *NEW* value (e.g. 0x616263).


You may be trying to make a simple rule that only "untyped" Scalar values
can auto-convert. So {my Str $a = my Int $b} is obviously wrong, while
{my Str $a = 123} can be obviously correct, because literals are "untyped"
Scalars. I suspect the conversion rules will be a lot more complicated
than that. "There is no general rule for converting a list into a scalar"
and all that...

~ John Williams

Me

unread,
Apr 18, 2003, 5:35:38 PM4/18/03
to Hod...@writeme.com, Michael Lazzaro, perl6-l...@perl.org
> Agreed. Can a hash key be a non-string now?
> Could the key itself be a valid and usable object?

I'm pretty sure @Larry has said yes to both.


> > There is no such thing as an "untyped" value. All values have
types,
> > even if that type is merely the root junctive, C<Scalar>.
>
> ~frown~
> So a literal 1 has no type until you use it

"Literal scalar values are ALWAYS of type C<Scalar>."
A literal 1 is of type Scalar.


--
ralph

Michael Lazzaro

unread,
Apr 18, 2003, 5:52:01 PM4/18/03
to John Williams, perl6-l...@perl.org

On Friday, April 18, 2003, at 02:34 PM, John Williams wrote:
> It seems like you are setting up Scalar as a grand-unifying Junction
> instead of a grand-unifying base class, and the Junction definition is
> even worse.

It is my strong impression that that's what the design team is after,
yes. That C<Scalar> is a junction, that is. Among the more recent
evidence is:

On Sunday, April 13, 2003, at 09:41 PM, Damian Conway wrote:
> Deborah Ariel Pickett wrote:
>
>> Literal Type
>> ----------------------------------------
>> undef Scalar
>
> Just Scalar.
>
>> What if I want a literal that's of a different type?
>
> You can't have it. Not without messing about with the parser, at least.


So pretty sure.

Mind you, that means we have *three* things that we're all trying to
call "Scalar"

-- the container class that implements scalar variables, my $x is
Scalar;

-- the mother-of-all-scalar-types, a root class that both Int and Str
belong to

-- the junction-of-all-scalar-types, the default type that something is
(for example, a literal) if you don't give it a specific type.

Oh, and fourth, the word "scalar" in the general sense, meaning atomic
value, as opposed to collection of values.

So it's small wonder we're getting confused.

MikeL

Michael Lazzaro

unread,
Apr 18, 2003, 5:52:50 PM4/18/03
to Hod...@writeme.com, perl6-l...@perl.org

On Friday, April 18, 2003, at 02:07 PM, Paul wrote:
>> [2.5] The statement:
>>
>> my $i is Foo;
>>
>> declares that the variable $i is implemented by the class C<Foo> --
>> that is, that the container itself is implemented by a C<Foo> object,
>> which is expected to implement the same interfaces as the default
>> container class, C<ScalarC>. This is how C<tie> behavior will
>> typically be implemented in Perl6. C<$i> remains an "untyped"
>> variable, which may store values of any scalar type.
>
> This could use some clarification, but I think I get it. You're
> thinking in interface terms. Foo must be able to do what $i is likely
> to be required to do, but can implement the methods to do .STORE,
> .FETCH, .toString, etc.

Actually, I'm personally almost certain that Foo must directly inherit
from ScalarC, eg C<class Foo is ScalarC>, in order to use Foo as a
container class. But saying "same interface as ScalarC" is a bit more
generic, since we don't know yet if or how proper interfaces will be
described.


>> [3. Literal Values]
>>
>> [3.1] Literal scalar values are ALWAYS of type C<Scalar>. The type
>> C<Scalar> is a junction of all other scalar types, e.g.
>> int|Int|str|Str|Ref|Code|etc.
>>
>> ref( 1 ); # returns Scalar;
>> ref( '1' ); # returns Scalar;
>
> Ok, that took me a minute, but it can't include Array and Hash in that
> juncture, can it? Those are collections, scalars are not. It most
> certainly *does* include Refs to those types, however.

Right.


>> Though they may look the part, literals are never of type int, str,
>> Int, Str, etc, however they may easily be transformed into those
>> other types.
>
> That is a little harder to digest, but types are an artifact of context
> and expectation, so 5 - "abc" could be construed as 5, because the
> compiler would theoretically coerce "abc" to it's numeric equivelent,
> zero. Am I following correctly?

Yes. The C<-> operator expects a numeric context on both sides, so the
C<Scalar>-typed C<5> and C<"abc"> are both automagically coerced to
numerics by that statement. C<Scalar> knows to produce a numeric or
string upon request.

In fact, it is highly likely that the numeric operators, automagically
coerce -all- possible values into numeric context, even arbitrary
objects: (OK, this part's hypothetical. But 80% sure.)

$obj1 - $obj2

IF those objects have a defined method of numerification. Same with
string operators, etc. We need verification, but this has been
*strongly* implied.

Note, for example, that in order to change a strongly-typed string to a
strongly-typed integer, all you'd need to do is say:

my $s = '123';
my Int $i = +$s;

because the unary + is doing the coercion for you. But just

my $s = '123';
my Int $i = $s;

wouldn't work.


>> There is no such thing as an "untyped" value. All values have types,
>> even if that type is merely the root junctive, C<Scalar>.
>
> ~frown~
> So a literal 1 has no type until you use it, but when you do that it
> becomes a value that must be typed; context is evaluated and the
> resulting value is of the desired type? A nonliteral, on the other
> hand, is *already* typed, so cross-assignment can be tested for
> correct-ness.
> I agree with the statement you've made, but elaboration hurts me.

Not quite: the literal 1 has a type to begin with -- the type
C<Scalar>. C<Scalar> is highly magical, and knows to coerce to other
types at will. So

my Int $i = 1;

Is imposing C<Int> context on the C<Scalar> value C<1>, which causes
the C<Scalar> to spit out it's C<Int>ification, which is the
C<Int>-typed one.


>> [3.2] The statement:
>> [3.3] In the code:


>
> Sounds like handwaving.
> Sounds like *correct* handwaving, though.

The part about .STORE is handwaving, definitely. We have no assurance
it will be called .STORE, or how exactly container objects will be
defined.

>> [3.5] The behavior of the junction type C<Scalar> is such that the
>> following are always true:
>>
>> my Int $x = 123; # stores Int-typed 123
>> my Int $x = "123"; # stores Int-typed 123
>> my Str $x = 123; # stores Str-typed "123"
>> my Str $x = "123"; # stores Str-typed "123"
>>
>> This allows literal numeric and string values to be used
>> interchangeably.
>
> Ok, maybe, since "123" is a literal, given the premise above.
> We're obviously into hypothetica now, though.

I don't think so -- or rather, if we are, I'd *really* like to know.
Past implication from the design team has been that, indeed, literals
were C<Scalar> junctives. That would seem to imply all of the
described behaviors must be true.


MikeL

Michael Lazzaro

unread,
Apr 18, 2003, 6:01:58 PM4/18/03
to Me, perl6-l...@perl.org

On Friday, April 18, 2003, at 02:22 PM, Me wrote:
>> [2.3] The statements:
>>
>> my Int $i;
>> my $i is ScalarC of Int;
>>
>> both declare that the variable $i may only hold values of type C<Int>,
>> or values derived from type C<Int>
>
> Right.
>
>> or values of a type with the same interface as C<Int>.
>
> 1. As Luke proposed, this could be inferred rather than
> explicit, ie if a value can be an Int (based on its sigs
> etc.) then it is an Int. It doesn't need to explicitly
> say that it implements Int.

I haven't put a whole ton of thought into it, I admit, but my own
objection to that approach would be the one Damian pointed out -- that
it's awfully easy to "accidentally" describe two things as having the
same interface, when actually you just happened to give their methods
the same names. I'd be very surprised if that would work well in
complex, real-world programs.

Personally, I would prefer having to explicitly name the interfaces a
class implements, via C<can> or similar. So a Foo can only be used as
an Int if, somewhere, you _explicitly_ told it that it can.

MikeL

Paul Johnson

unread,
Apr 18, 2003, 6:07:11 PM4/18/03
to Me, Hod...@writeme.com, Michael Lazzaro, perl6-l...@perl.org
On Fri, Apr 18, 2003 at 04:35:38PM -0500, Me wrote:

> I'm pretty sure @Larry has said yes to both.

@Larry! What a great idea, providing @Larry > 1.

--
Paul Johnson - pa...@pjcj.net
http://www.pjcj.net

Paul

unread,
Apr 18, 2003, 6:08:00 PM4/18/03
to John Williams, Michael Lazzaro, perl6-l...@perl.org

--- John Williams <will...@tni.com> wrote:
> Excellent stuff generally, but (appologies in advance) this
> Section 3 just doesn't work for me. I'm mostly going to present
> how I think about it as an alternate point-of-view, in order to
> try not to be negative.
>
> I'm willing to agree to disagree while we wait for the design team.

Agreed, though I will still try to make similar constructive
observations.



> > There is no such thing as an "untyped" value. All values have
> > types, even if that type is merely the root junctive, C<Scalar>.
>
> It seems like you are setting up Scalar as a grand-unifying Junction
> instead of a grand-unifying base class, and the Junction definition
> is even worse.
>
> Alternate POV: Each literal value has a specific type given to it
> by the compiler. 1 is an Int (or maybe int), "2" is a Str, 3=>4
> is a Pair, [5,6] is an Array, etc. It looks like an Int, so it's
> an Int.

I disagree. If it must be typed, default to Scalar.
It *is* actually a type, as evidenced by the fact that a ref can be of
that type. It is also the most generic possible thing.

> > [3.2] The statement:
> >
> > my $i = 1;
> >
> > stores the C<Scalar> C<1> into the C<Scalar>-typed variable
> > C<$i>, such that
> >
> > ref( $i );
> >
> > returns C<Scalar>.
>
> Alternate POV:
>
> my $i;
>
> creates a variable with a Scalar(P) variable type, but with no
> particular value type (it's of/returns trait is undefined).
> Thus it can be considered an "untyped" variable.
>
> It's value type changes with the value. In this example the current
> value type is, well, whatever the type of undef is. And undef's
> type is probably not Scalar, since %h and @a can also be undef.

But C<my $i;> isn't C<my $i = 1;>, which was the example. Your
statement isn't an alternate.

> > [3.3] In the code:
> >
> > my Int $i;
> > $i = 1;
> >
> > the literal value C<1> is of type C<Scalar>, NOT of type C<Int>.
> > When the C<Scalar> value C<1> is placed into the C<Int>-typed
> > variable $i, the resulting value is of type C<Int>. Specifically,
> > the action:
> >
> > $i.STORE( 1 );
> >
> > places the C<Int> value of the literal Scalar C<1> into $i,
> > discarding other aspects of the value, such that
> >
> > ref( $i );
> >
> > returns C<Int>.
>
> Alternate POV:
>
> The literal value C<1> is of type C<Int> (or C<int>). It is still
> Int whether it is stored in a my $i or a my Int $i.

C<1> is not an Int unless used as an Int. It's a scalar.

my $s = 1;
print "foo" if $s ~~ "1"; # prints

> > [3.5] The behavior of the junction type C<Scalar> is such that the
> > following are always true:
> >
> > my Int $x = 123; # stores Int-typed 123
> > my Int $x = "123"; # stores Int-typed 123
> > my Str $x = 123; # stores Str-typed "123"
> > my Str $x = "123"; # stores Str-typed "123"
> >
> > This allows literal numeric and string values to be used
> > interchangeably.
>
> I'm avoiding the conversion/coersion thread. But I will express my
> opinion that type conversion has very little, if anything, to do with
> inheritance, and that context plays a very major role.
>
> Well, I guess I'm being sucked into it some anyway, to address the
> things
> I object to in this section.
>
> Alternate POV:
>
> my Str $x = 123;
>
> C<123> is of type C<Int>, because that is the type the compiler
> gave it when it created that value in the compiled code. (You
> wrote it as an int, so it stored in the bit pattern 0x7B probably.)

I disagree rather strongly with this assumption. The compiler isn't C.
It will store it as whatever value the design team thinks is
appropriate. Until I hear something authoritatively contradictory, I'd
assume it's a Scalar, with all that implies.

> You may be trying to make a simple rule that only "untyped" Scalar
> values can auto-convert. So {my Str $a = my Int $b} is obviously
> wrong, while {my Str $a = 123} can be obviously correct, because
> literals are "untyped" Scalars. I suspect the conversion rules
> will be a lot more complicated than that. "There is no general
> rule for converting a list into a scalar" and all that...

Why is {my Str $a = my Int $b} obviously wrong? Damian seems to think
Ints will stringify on demand.

And I don't *like* that {my Str $a = 123} is probably correct, and
won't be typing it that way, but I have to agree that it probably is.
(~sigh~)

But your point here is *definitely* valid -- just like converting a
list to a scalar, it'll probably only have one simple rule -- each
thing will try to DWIN, for some definition of DWIM, and not the *same* definition.

Paul

unread,
Apr 18, 2003, 6:10:05 PM4/18/03
to Me, Hod...@writeme.com, Michael Lazzaro, perl6-l...@perl.org

--- Me <m...@self-reference.com> wrote:
> > Agreed. Can a hash key be a non-string now?
> > Could the key itself be a valid and usable object?
>
> I'm pretty sure @Larry has said yes to both.

SWEET!

> > > There is no such thing as an "untyped" value. All values have
> > > types, even if that type is merely the root junctive, C<Scalar>.
> >
> > ~frown~
> > So a literal 1 has no type until you use it
>
> "Literal scalar values are ALWAYS of type C<Scalar>."
> A literal 1 is of type Scalar.

*whew*

Paul

unread,
Apr 18, 2003, 6:15:13 PM4/18/03
to Michael Lazzaro, John Williams, perl6-l...@perl.org
> Mind you, that means we have *three* things that we're all trying to
> call "Scalar"
>
> -- the container class that implements scalar variables, my $x is
> Scalar;
>
> -- the mother-of-all-scalar-types, a root class that both Int and Str
> belong to

I don't know about this one, at least as far as Str and Int go.
I see your point, but as an aside, they may not be implemented that
way.

> -- the junction-of-all-scalar-types, the default type that something
> is (for example, a literal) if you don't give it a specific type.

> Oh, and fourth, the word "scalar" in the general sense, meaning
> atomic value, as opposed to collection of values.
>
> So it's small wonder we're getting confused.

Ab-so-damnedly-lute-ly.

Paul

unread,
Apr 18, 2003, 6:22:50 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
>
> On Friday, April 18, 2003, at 02:07 PM, Paul wrote:
> >> [2.5] The statement:
> >>
> >> my $i is Foo;
> >>
> >> declares that the variable $i is implemented by the class C<Foo>
> --
> >> that is, that the container itself is implemented by a C<Foo>
> object,
> >> which is expected to implement the same interfaces as the default
> >> container class, C<ScalarC>. This is how C<tie> behavior will
> >> typically be implemented in Perl6. C<$i> remains an "untyped"
> >> variable, which may store values of any scalar type.
> >
> > This could use some clarification, but I think I get it. You're
> > thinking in interface terms. Foo must be able to do what $i is
> likely
> > to be required to do, but can implement the methods to do .STORE,
> > .FETCH, .toString, etc.
>
> Actually, I'm personally almost certain that Foo must directly
> inherit from ScalarC, eg C<class Foo is ScalarC>, in order to use
> Foo as a container class. But saying "same interface as ScalarC"
> is a bit more generic, since we don't know yet if or how proper
> interfaces will be described.

Time to go home, so I won't comment on this. :)

> In fact, it is highly likely that the numeric operators,
> automagically coerce -all- possible values into numeric context,
> even arbitrary objects: (OK, this part's hypothetical. But 80%
> sure.)
>
> $obj1 - $obj2
>
> IF those objects have a defined method of numerification. Same with
> string operators, etc. We need verification, but this has been
> *strongly* implied.

lol -- maybe they'll all just auto-stringify first, since you can
numify a string....OW! Hey, who threw that?!? ;o]



> >> There is no such thing as an "untyped" value. All values have
> >> types, even if that type is merely the root junctive, C<Scalar>.
> >
> > ~frown~
> > So a literal 1 has no type until you use it, but when you do that
> > it becomes a value that must be typed; context is evaluated and the
> > resulting value is of the desired type? A nonliteral, on the other
> > hand, is *already* typed, so cross-assignment can be tested for
> > correct-ness. I agree with the statement you've made, but
> > elaboration hurts me.
>
> Not quite: the literal 1 has a type to begin with -- the type
> C<Scalar>. C<Scalar> is highly magical, and knows to coerce to other
> types at will. So
>
> my Int $i = 1;
>
> Is imposing C<Int> context on the C<Scalar> value C<1>, which causes
> the C<Scalar> to spit out it's C<Int>ification, which is the
> C<Int>-typed one.

Maybe I misread, but I thought you said earlier that a literal was
effectively untyped. That was the basis for my comment.

Now we know -- literals are scalars, period. (Or collections of them :)



> >> [3.5] The behavior of the junction type C<Scalar> is such that the
> >> following are always true:
> >>
> >> my Int $x = 123; # stores Int-typed 123
> >> my Int $x = "123"; # stores Int-typed 123
> >> my Str $x = 123; # stores Str-typed "123"
> >> my Str $x = "123"; # stores Str-typed "123"
> >>
> >> This allows literal numeric and string values to be used
> >> interchangeably.
> >
> > Ok, maybe, since "123" is a literal, given the premise above.
> > We're obviously into hypothetica now, though.
>
> I don't think so -- or rather, if we are, I'd *really* like to know.
> Past implication from the design team has been that, indeed, literals
> were C<Scalar> junctives. That would seem to imply all of the
> described behaviors must be true.

Recent posts from the Damian confirm your thinking.
Guess I'll have to get used to it. :)

Michael Lazzaro

unread,
Apr 18, 2003, 6:46:25 PM4/18/03
to Hod...@writeme.com, John Williams, perl6-l...@perl.org

On Friday, April 18, 2003, at 03:08 PM, Paul wrote:
> Why is {my Str $a = my Int $b} obviously wrong? Damian seems to think
> Ints will stringify on demand.

Yeah, I've seen that too. There may be specific magic involved with
Str/Int/Num, perhaps?

My personal objection to having C< my Str $a = my Int $b > NOT give an
error, as Damian suggests, is that implies that Strs and Ints may be
used interchangably. And frankly, I'd really rather they weren't:

multi foo( $self, Int $x ) {...}
multi foo( $self, Str $x ) {...}

Granted, in the above code, it'd always find one variant to be "closer"
than the other, but it would still seem to imply that if one of those
wasn't there, it would incessantly be autoconverting for you such that
it would _look_ like both of them were there.

I'd be annoyed if I couldn't get the behavior of saying that Str should
be allowed, but Int shouldn't, simply by removing one of those and
saying:

sub foo( $self, Int $x ) {...} # No Strs, dammit!

*** E.g. it seems a Pandora's Box, allowing variants to match where
they really shouldn't, and allowing runtime conversions to take place
when you really would have rather _known_ they were taking place, so
that you could do something to prevent them. ***

I tend to come down on the ultra-strict typing side of things, simply
because I see no other way to get the speed out of Perl6 that I'm going
to need to get. So I'd rather you had to say something like:

my Str $a = ~(my Int $b);

to force the issue. But it is true, for the specific cases of
int/Int/num/Num/str/Str I would not collapse in horror if things were
more magical then for "normal" types and classes.

MikeL

Me

unread,
Apr 18, 2003, 6:49:11 PM4/18/03
to Michael Lazzaro, perl6-l...@perl.org
> [inferred types]

>
> I haven't put a whole ton of thought into it, I admit,
> but my own objection to that approach would be the one
> Damian pointed out -- that it's awfully easy to "accidentally"
> describe two things as having the same interface, when
> actually you just happened to give their methods the same
> names. I'd be very surprised if that would work well in
> complex, real-world programs.

Arguing from a logical standpoint, for a type inference
system to have a chance of being useful, it needs to
look at a lot more detail than just method names. The
norm is to look at all relevant signature detail. If
all necessary methods, compile-time assertions, etc.
match, then even accidental compatibility is almost
certainly the very happy accident one wants.

Arguing from an empirical standpoint, Haskell and many
other languages have proven that inferred types can work
great for type checking in complex, real-world programs.

Of all the type related technologies and approaches that
have emerged in the last decade or so, inferred types
is imo one of the most exciting and most perlish.


> Personally, I would prefer having to explicitly name
> the interfaces a class implements, via C<can> or similar.
> So a Foo can only be used as an Int if, somewhere, you
> _explicitly_ told it that it can.

Right. But that preference is of great consequence as
a choice made by a programmer, when considering how
malleable that programmer's code is, and is of a zillion
times greater consequence if it's a choice made by @Larry
as being the only way to do it in perl6.

It does feel like it could possibly be bolted on later.
My hope is just to see it fleshed out enough that its
viability (rather than desirability) for p6 is assesed
and if it looks good then the right parrot and perl
syntax sugar holes and hooks are in place.

--
ralph

Damian Conway

unread,
Apr 18, 2003, 7:04:57 PM4/18/03
to perl6-l...@perl.org
Michael Lazzaro wrote:
>
> On Friday, April 18, 2003, at 03:08 PM, Paul wrote:
>
>> Why is {my Str $a = my Int $b} obviously wrong? Damian seems to think
>> Ints will stringify on demand.
>
> Yeah, I've seen that too. There may be specific magic involved with
> Str/Int/Num, perhaps?

Yes. The same magic as in Perl 5. But also see below.


> My personal objection to having C< my Str $a = my Int $b > NOT give an
> error, as Damian suggests, is that implies that Strs and Ints may be
> used interchangably. And frankly, I'd really rather they weren't
>
> multi foo( $self, Int $x ) {...}
> multi foo( $self, Str $x ) {...}

The problem is that variable types merely restrict the types of value that a
variable must assigned or bound to, *not* the type of value/variable that the
assigned-or-bound value originally came from. Any value that can adapt itself
to produce the required type is allowed to do so.

At least, that's my understanding of Larry's intent.


> Granted, in the above code, it'd always find one variant to be "closer"
> than the other, but it would still seem to imply that if one of those
> wasn't there, it would incessantly be autoconverting for you such that
> it would _look_ like both of them were there.

Yep.


> I'd be annoyed if I couldn't get the behavior of saying that Str should
> be allowed, but Int shouldn't, simply by removing one of those and saying:
>
> sub foo( $self, Int $x ) {...} # No Strs, dammit!

That C,dammit> operator certainly is handy, isn't it. ;-)

I would expect that there will be a way to accomplish that.
Possibly with a trait on the parameter; possibly with a form of C<use strict>;
otherwise (eventually) with a Damianical module.

Damian

Me

unread,
Apr 18, 2003, 7:07:50 PM4/18/03
to Hod...@writeme.com, Michael Lazzaro, John Williams, perl6-l...@perl.org
> [concerns regarding implicit Str/Num etc. conversion magic]

What about a container class trait that determines whether
implicit conversion magic occurs?

class Foo is Scalar is coercive;

my Int $foo is Foo;
my Str $bar = "33";
$foo = $bar; # ok

There's plenty of other ways to skin this trait-based
cat syntactically, but I think it would best fit on
container classes as above. Perhaps C<will coerce {}>
with some C<.toXXX when Str;> statements or whatever
so that there's more scope to control any coercion.

--
ralph

Paul

unread,
Apr 18, 2003, 7:27:45 PM4/18/03
to Michael Lazzaro, John Williams, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
>

*I* tend to come down on the ultra-strict side of typing because if I
don't want strong, strict types I can just make everything scalars. If
I SAY Int, I MEAN Int, and hell, there ARE explicit context specifiers.
Thos should be enough to say "okay, convert *here*" so that NOT using
them is an error.

But you could always do this:

multi foo( $self, Int $x ) {...}

multi foo( $self, Str $x ) { die "I said *Int*, dammit!" }

except that then you're stuck with inclusive exclusion, instead of
exclusive inclusion.

Paul

unread,
Apr 18, 2003, 7:35:48 PM4/18/03
to Damian Conway, perl6-l...@perl.org
> >> Why is {my Str $a = my Int $b} obviously wrong? Damian seems to
> >> think Ints will stringify on demand.
> >
> > Yeah, I've seen that too. There may be specific magic involved
> > with Str/Int/Num, perhaps?
>
> Yes. The same magic as in Perl 5. But also see below.
>
> > My personal objection to having C< my Str $a = my Int $b > NOT
> > give an error, as Damian suggests, is that implies that Strs
> > and Ints may be used interchangably. And frankly, I'd really
> > rather they weren't
> >
> > multi foo( $self, Int $x ) {...}
> > multi foo( $self, Str $x ) {...}
>
> The problem is that variable types merely restrict the types
> of value that a variable must assigned or bound to, *not* the
> type of value/variable that the assigned-or-bound value
> originally came from. Any value that can adapt itself
> to produce the required type is allowed to do so.
>
> At least, that's my understanding of Larry's intent.

...oooOOOOoooohhhhhhh......
Wait a sec....little clicking noises seem to indicate the light may
come on any second now.....

> > Granted, in the above code, it'd always find one variant to be
> > "closer" than the other, but it would still seem to imply that
> > if one of those wasn't there, it would incessantly be
> > autoconverting for you such that it would _look_ like both
> > of them were there.
>
> Yep.

Hmm.... a feature, then?

> > I'd be annoyed if I couldn't get the behavior of saying that
> > Str should be allowed, but Int shouldn't, simply by removing
> > one of those and saying:
> >
> > sub foo( $self, Int $x ) {...} # No Strs, dammit!
>

> That C<dammit> operator certainly is handy, isn't it. ;-)

Yes! Give us the dammit()!!
Give us the dammit(), dammit!! :)

> I would expect that there will be a way to accomplish that.
> Possibly with a trait on the parameter; possibly with a form
> of C<use strict>; otherwise (eventually) with a Damianical module.

can I get a "mwuahahahahahaaaa......"

Mlazzaro

unread,
Apr 19, 2003, 12:11:50 PM4/19/03
to Damian Conway, perl6-l...@perl.org
Damian Conway wrote:

> Michael Lazzaro wrote:
> The problem is that variable types merely restrict the types of value that a
> variable must assigned or bound to, *not* the type of value/variable that the
> assigned-or-bound value originally came from. Any value that can adapt itself
> to produce the required type is allowed to do so.
>
> At least, that's my understanding of Larry's intent.

So, in other words, the statement:

my Int $i = $s;

does not have the effect of "assign $s to $i, but throw an error if the
value in $s isn't an Int, or derived from an Int", but rather says
"coerce the value in $s to Int, regardless of its current type, but
throw an error if no coersion method can be found."

In other words, *all* assignments autocoerce between types. Including:

my Int $x = $foo; # where $foo of type C<Foo>
my Str $x = $foo;
my Baz $x = $foo;

... and even ...

sub foo(Int $x);

foo($obj);
foo($str);

... providing each of those vars/types have a method of coercion to Int.


Hmm. I confess that after working primarily in C/C++/Java, I've always
wanted that behavior. But I've never been able to convince myself that
it could be allowed without introducing "silent" object replications at
runtime, e.g. loads of inefficiency. Hmm.

MikeL

Mlazzaro

unread,
Apr 19, 2003, 12:27:18 PM4/19/03
to Hod...@writeme.com, John Williams, perl6-l...@perl.org
Paul wrote:
> *I* tend to come down on the ultra-strict side of typing because if I
> don't want strong, strict types I can just make everything scalars. If
> I SAY Int, I MEAN Int, and hell, there ARE explicit context specifiers.
> Thos should be enough to say "okay, convert *here*" so that NOT using
> them is an error.

Yeah. I mean, I like the idea of autocoercion, I'm just worried about
the implications. If you said code that boiled down to:

my Str $s = '123';


my Int $i = $s;

my Int $j = $s;
my Int $k = $s;

... you're string-to-int converting three times -- and if it's a big
piece of code, you probably aren't going to notice that, but if you need
speed you probably want to be *warned* you're being an idiot, by being
forced to coerce to string manually, like you "should" have done:

my Str $s = '123';
my Int $x = $s as Str;

my Int $i = $s; # more efficient
my Int $j = $s;
my Int $k = $s;

So it's safe to say I have really, __really__ mixed feelings about autocoercion.

MikeL

Mlazzaro

unread,
Apr 19, 2003, 12:29:48 PM4/19/03
to Hod...@writeme.com, John Williams, perl6-l...@perl.org

Dammit, I mangled my second example. It should be:

mlazzaro wrote:
> forced to coerce to Int manually, like you "should" have done:


>
> my Str $s = '123';

> my Int $x = $s as Int;
>
> my Int $i = $x; # more efficient
> my Int $j = $x;
> my Int $k = $x;

Sigh.

MikeL

Larry Wall

unread,
Apr 19, 2003, 12:43:42 PM4/19/03
to perl6-l...@perl.org
On Sat, Apr 19, 2003 at 09:04:57AM +1000, Damian Conway wrote:
: The problem is that variable types merely restrict the types of value that
: a variable must assigned or bound to, *not* the type of value/variable that
: the assigned-or-bound value originally came from. Any value that can adapt
: itself to produce the required type is allowed to do so.
:
: At least, that's my understanding of Larry's intent.

Close. That's the default approach, but the caller is allowed to
restrict the degree of adaptation. The one invariant in all this is
that formal parameter is expected to behave as it is declared *while*
it is bound. It shouldn't care about before, or after, or anything else
outside--that'd be a violation of "excapsulation", as it were.

: >Granted, in the above code, it'd always find one variant to be "closer"

: >than the other, but it would still seem to imply that if one of those
: >wasn't there, it would incessantly be autoconverting for you such that
: >it would _look_ like both of them were there.
:
: Yep.
:
:
: >I'd be annoyed if I couldn't get the behavior of saying that Str should
: >be allowed, but Int shouldn't, simply by removing one of those and saying:
: >
: > sub foo( $self, Int $x ) {...} # No Strs, dammit!
:
: That C,dammit> operator certainly is handy, isn't it. ;-)

Around here you're likelier to get what you want with a C<,please> operator. :-)

: I would expect that there will be a way to accomplish that.
: Possibly with a trait on the parameter; possibly with a form of C<use
: strict>; otherwise (eventually) with a Damianical module.

I think it's fine that a formal declaration enforces the contract
type internally. It seems unfair to let the contract also enforce
style externally. The IRS doesn't much care how gracefully I come up
with the money, as long as a certain number of dollars show up on
their doorstep periodically. They don't much care whether I slaved
over my tax forms for hours or hired someone else to do it for me.
Their basic interface (slightly oversimplified) is something like:

sub taxday (Form @forms, Bucks $money) returns Bucks { gov() }

To be sure, if you expect taxday() to return all the bucks you put
in, you may need to be ready to catch an IRS::Audit exception... :-)

Larry

Luke Palmer

unread,
Apr 19, 2003, 2:37:10 PM4/19/03
to mlaz...@cognitivity.com, Hod...@writeme.com, will...@tni.com, perl6-l...@perl.org

Efficiency is one of the least of my concerns. Like this might be a
common problem, and might be fixed with a "converted cache" on the
other side, or somesuch (like Perl 5 between strs and ints).

I've wanted automatic conversions to "just behave" in my other
programming escapades, but we can see problems with them by looking at
C++ after they were added.

Using a pseudo-syntax:

class Foo {
from Bar {...}
}
class Bar {
to Foo {...}
}
my Foo $x = Bar.new; # Bar to Foo or Foo from Bar?

That was remedied in C++ by one of those horrible dictations of style:
Make your conversions unambiguous, dummy! I consider that an
offensive solution.

class Fous {
from Int {...}
}
class Barre {
from Int {...}
}
multi uhoh(Fous $a);
multi uhoh(Barre $a);
uhoh(25); # &uhoh(Fous) or &uhoh(Barre)?

There are countless others that occur frequently in common practice.
C++ feels like it should whack you with an error in ambiguity, instead
of trying to figure it out itself. I agree.

And then there's this:

class A {
to B {...}
}
class B {
to C {...}
}
class C {
to D {...}
}
class D {}
sub pleaseno(D);
pleaseno(A.new);

Should that really call pleaseno()? I don't consider this a problem
in efficiency, I see it as a problem in semantics. Did you want it
to call that sub with your A converted three times? And the biggest
problem is, sometimes you did and sometimes you didn't. When you're
coding "straight", you usually don't. But if you're doing clever
things, this kind of conversion can be very useful.

But, considering the kinds of mysterious errors this could produce,
I'd go with not allowing this. And this is why I'm still unsure about
how Perl 6's implicit conversions will work, and whether there will be
any at all.

Luke

Luke Palmer

unread,
Apr 19, 2003, 2:39:12 PM4/19/03
to Hod...@writeme.com, mlaz...@cognitivity.com, will...@tni.com, perl6-l...@perl.org

Although this would work:

multi foo( $self, Int $x ) {...}

multi foo( $self, $x ) { die "I'm going to make you suffer!" }

But that's runtime, not compile time, for something that should be
compile time.

Luke

Mlazzaro

unread,
Apr 19, 2003, 3:35:06 PM4/19/03
to Luke Palmer, perl6-l...@perl.org

Luke Palmer wrote:
> I've wanted automatic conversions to "just behave" in my other
> programming escapades, but we can see problems with them by looking at
> C++ after they were added.

Re: C++, that's an excellent observation. C++ is very "unsatisfying" in
that regard. Java too.

> Using a pseudo-syntax:
>
> class Foo {
> from Bar {...}
> }
> class Bar {
> to Foo {...}
> }
> my Foo $x = Bar.new; # Bar to Foo or Foo from Bar?
>
> That was remedied in C++ by one of those horrible dictations of style:
> Make your conversions unambiguous, dummy! I consider that an
> offensive solution.
>
> class Fous {
> from Int {...}
> }
> class Barre {
> from Int {...}
> }
> multi uhoh(Fous $a);
> multi uhoh(Barre $a);
> uhoh(25); # &uhoh(Fous) or &uhoh(Barre)?

I think in that _particular_ case, I'd want the compiler to recognize
the ambiguity and carp about it, in the exact same way that other
multimethod variant searches would gag if the paths were equidistant
(assuming that's still true). The example I more worry about is:

class Foo { from Bar {...} }
class Bar { to Foo {...} }

sub blah(Foo $f);

blah(Bar.new); # which path does it take, the 'from' or 'to'?

My own solution to this would be to always assume "from" paths are
superior to "to" paths, because 'from's represent constructors... 'to's
represent secondary or "backup" conversions, to be used if you can't
modify the source of the target class to include a new "from".

Alternatively, placing a "to" in a package could be considered literally
_identical_ to placing a "from" in the target class' package -- it would
actually place the method as a 'from' in the target class -- such that
the compiler would throw an err if it found duplicative "from" and "to"
declarations, again similar to multimethods? But that strikes me as
hard to maintain.


> There are countless others that occur frequently in common practice.
> C++ feels like it should whack you with an error in ambiguity, instead
> of trying to figure it out itself. I agree.
>
> And then there's this:
>
> class A { to B {...} }
> class B { to C {...} }
> class C { to D {...} }
> class D {}
> sub pleaseno(D);
> pleaseno(A.new);
>
> Should that really call pleaseno()? I don't consider this a problem
> in efficiency, I see it as a problem in semantics. Did you want it
> to call that sub with your A converted three times? And the biggest
> problem is, sometimes you did and sometimes you didn't. When you're
> coding "straight", you usually don't. But if you're doing clever
> things, this kind of conversion can be very useful.

Yes. It is magical, and wonderous, and horrible all at the same time.
I'd love for that to work, because it would mean you wouldn't have to
put those damn method variants for every possible parameter type (Java), but...

In situations I've worked in where autoconversion is meant to be
allowed, I've always run across the particular problem of Strings.
Namely, that nearly every object under the sun has a string
representation, and that nearly every object under the sun allows
construction from a serialized string representation.

So if you allow autoconversion "chains", where you allow the compiler to
look for "the best way to convert an arbitrary object of type Foo to
type Baz"...

class Foo {...} # two unrelated classes
class Baz {...}
...
my Baz = $foo;

if both those objects can be converted to and from strings, then the
compiler _always_ thinks you can convert between a Foo and a Baz... it's
_always_ going to think it's finding a coercion path, through
stringification -- even though in reality the string representations of
those objects aren't even remotely compatible, and the two objects have
absolutely nothing in common, and it will gag runtime when it actually
attempts to do so.

So autoconversion of types, if done too liberally, pretty much
evaporates strong typing entirely. That's my worry -- how to get the
wonderousness of what we mean, without letting the compiler get carried away.

> But, considering the kinds of mysterious errors this could produce,
> I'd go with not allowing this. And this is why I'm still unsure about
> how Perl 6's implicit conversions will work, and whether there will be
> any at all.
>
> Luke

Yep. Dunno.

MikeL

Damian Conway

unread,
Apr 19, 2003, 5:54:23 PM4/19/03
to Larry Wall, perl6-l...@perl.org
Larry wrote:

> : I would expect that there will be a way to accomplish that.
> : Possibly with a trait on the parameter; possibly with a form of C<use
> : strict>; otherwise (eventually) with a Damianical module.
>
> I think it's fine that a formal declaration enforces the contract
> type internally. It seems unfair to let the contract also enforce
> style externally. The IRS doesn't much care how gracefully I come up
> with the money, as long as a certain number of dollars show up on
> their doorstep periodically.

Hmmmmmm. Even within your metaphor, I'm not sure that's true. The IRS
certainly does care if the money is counterfeit. And they (or their close
personal friends at the DOJ) also care if it's stolen.

So, whilst I'm very happy that Perl 6 will, by default, auto-coerce arguments
according to parameter types, I would also like the option to tell Perl 6 that
I prefer strict static typechecking, and would it please *not* intercept my
tax payment and helpfully substitute laundered cartel money just because I
accidentally sent in a kilo of Bolivian Gold, rather than a kilo of gold.

As you have already acknowledged -- by providing both C<is ref> and C<is rw>
-- there are cases where one would much rather have Perl say "you can't do
that, so I won't let you", than have it say "I let you, but you shouldn't have
done that".

Damian

Paul

unread,
Apr 20, 2003, 12:18:35 AM4/20/03
to mlazzaro, John Williams, perl6-l...@perl.org

--- mlazzaro <mlaz...@cognitivity.com> wrote:
> Paul wrote:
> > *I* tend to come down on the ultra-strict side of typing
> > because if I don't want strong, strict types I can just make
> > everything scalars. If I SAY Int, I MEAN Int, and hell, there
> > ARE explicit context specifiers. Those should be enough to say

> > "okay, convert *here*" so that NOT using them is an error.
>
> Yeah. I mean, I like the idea of autocoercion, I'm just worried
> about the implications. If you said code that boiled down to:
>
> my Str $s = '123';
> my Int $i = $s;
> my Int $j = $s;
> my Int $k = $s;
>
> ... you're string-to-int converting three times -- and if it's a big
> piece of code, you probably aren't going to notice that, but if you
> need speed you probably want to be *warned* you're being an idiot,
> by being forced to coerce to string manually, like you "should" have
> done:
>
> my Str $s = '123';
> my Int $x = $s as Str;
>
> my Int $i = $s; # more efficient
> my Int $j = $s;
> my Int $k = $s;

I assume those = $s's should've been = $x's? :)

> So it's safe to say I have really, __really__ mixed feelings about
> autocoercion.
> MikeL

True, *BUT* -- Dan says it *will* autocoerce as the defult, but will
bitch if warnings are on, and blow up under strict. If I understood
that right, it's *exactly* the right behavior. That way if I explicitly
want free-floating, auto-coercing data, I just use plain scalars. If I
want types, they'll be forgiving, but if I enable warnings they'll
probably tell me if I do something stupid. And if I enable strict (the
default in classes and modules!) then it'll Just Say No.

Hey, Damian, am I on line with this?
I understand what it *will* do, but do I have a grasp on *when*?

Paul

unread,
Apr 20, 2003, 12:23:42 AM4/20/03
to Larry Wall, perl6-l...@perl.org

--- Larry Wall <la...@wall.org> wrote:
> : That C,dammit> operator certainly is handy, isn't it. ;-)
>
> Around here you're likelier to get what you want with a C<,please>
> operator. :-)

You know, even though it lacks the humor factor, that really is also
kind of a cool idea. I think it would ger\nerally increase my
likelihood to use a language if it actually had a please() operator,
except for the fact that this is Perl, which I'll be using anyway,
whether it does or not. :)

Paul

unread,
Apr 20, 2003, 12:30:07 AM4/20/03
to Luke Palmer, mlaz...@cognitivity.com, Hod...@writeme.com, will...@tni.com, perl6-l...@perl.org

pragmata actually handle this reasonably well.
You want flexibility? The default is to fish until you find it, or
figure out the pond is empty for sure. You want clarity? C<use strict;>
and these will probably blow up in your face.

You want both? C<use strict;> and say C<pleaseno(A.new as D);> or be
prepared to catch that exception. :)

Paul

unread,
Apr 20, 2003, 12:33:13 AM4/20/03
to Luke Palmer, Hod...@writeme.com, mlaz...@cognitivity.com, will...@tni.com, perl6-l...@perl.org
> > But you could always do this:
> >
> > multi foo( $self, Int $x ) {...}
> > multi foo( $self, Str $x ) { die "I said *Int*, dammit!" }
> >
> > except that then you're stuck with inclusive exclusion, instead of
> > exclusive inclusion.
>
> Although this would work:
>
> multi foo( $self, Int $x ) {...}
> multi foo( $self, $x ) { die "I'm going to make you suffer!"
> }
>
> But that's runtime, not compile time, for something that should be
> compile time.

Even better (and I think this is maybe where we want to go anyway):

use strict;
multi foo($me, Int $x) {...}
# and that's all; strict says "if it ain't Int, it ain't IT."

Paul

unread,
Apr 20, 2003, 12:38:45 AM4/20/03
to mlazzaro, Luke Palmer, perl6-l...@perl.org
> So autoconversion of types, if done too liberally, pretty much
> evaporates strong typing entirely. That's my worry -- how to get the
> wonderousness of what we mean, without letting the compiler get
> carried away.

Unless the lightbulb I'm seeing in my head is high blood pressure,

no strict types;

gives you magical autoconversions, and

use strict types;

gives you magical type enforcement.

Damian Conway

unread,
Apr 20, 2003, 1:40:55 AM4/20/03
to perl6-l...@perl.org
Paul wrote:

> True, *BUT* -- Dan says it *will* autocoerce as the defult, but will
> bitch if warnings are on, and blow up under strict. If I understood
> that right, it's *exactly* the right behavior. That way if I explicitly
> want free-floating, auto-coercing data, I just use plain scalars. If I
> want types, they'll be forgiving, but if I enable warnings they'll
> probably tell me if I do something stupid. And if I enable strict (the
> default in classes and modules!) then it'll Just Say No.
>
> Hey, Damian, am I on line with this?
> I understand what it *will* do, but do I have a grasp on *when*?

You've pretty much summarized what I'd *like* to see, though I don't know
whether C<strict> will be the default for modules and classes, unless you mean
the cultural default.

What we *will* see is, as always, ultimately up to Larry. :-)

Damian

Paul

unread,
Apr 20, 2003, 2:30:15 AM4/20/03
to Damian Conway, perl6-l...@perl.org

Er? I thought Larry had already said he pretty much was going to make
strict the default in modules and classes ("big code") but nonstrict
the default in the main script (more commonly "small code"). You could
still override either, of course, but that just made so much *sense*.

> What we *will* see is, as always, ultimately up to Larry. :-)
> Damian

He's done good work so far! :)

Mlazzaro

unread,
Apr 20, 2003, 3:17:17 AM4/20/03
to Hod...@writeme.com, Luke Palmer, perl6-l...@perl.org

Paul wrote:
> > So autoconversion of types, if done too liberally, pretty much
> > evaporates strong typing entirely. That's my worry -- how to get the
> > wonderousness of what we mean, without letting the compiler get
> > carried away.
>
> Unless the lightbulb I'm seeing in my head is high blood pressure,
>
> no strict types;
>
> gives you magical autoconversions, and
>
> use strict types;
>
> gives you magical type enforcement.

Yes, perhaps, but I still have the nagging suspicion that there's quite
a range of desirable behavior that lies somewhere between
all-coercions-on and all-coercions-off.

There are some types that _should_ always autocoerce.(?) C<int> to/from
C<Int>, for example. C<int> to C<num>, but not C<num> to C<int>;
C<int> to C<str>, obviously. And it'd be great if you could
specifically tell your Foo obj that it was always allowed to coerce to a
Baz object, if need be, independant of the more global 'strictness'
setting. And it'd be greater if, assuming a Baz could be coerced to a
Bar, the compiler then knew it could turn a Foo into a Bar by "chaining"
the coercions through Baz.

But my point with the "nearly everything can convert to and from
strings" example is that if we were to allow the "chaining" of
coercions, I think the compiler would *always* find a (very wrong) way
to coerce between any two types/classes, rendering the types absolutely
useless. Just 'cause a Foo can be turned into a string, and a Baz can
be obtained _from_ a string, doesn't mean that a Foo can be made into a
Baz. Thus, "chaining" in particular would appear to be nearly
impossible to get to behave correctly.(?) But I would dearly love to be
wrong about that.

Hmm. Unless 'type coercion' and 'serialization' are two different
concepts, such that serialization never plays with type coercion...
sort of 'greater' and 'lesser' coercions... No, not quite...

But these are just half-thoughts... dunno, I need to percolate these a
while. But do you see my concern, that I want a happy medium between
"always coerce" and "never coerce"?

MikeL

Jonathan Worthington

unread,
Apr 20, 2003, 8:55:07 PM4/20/03
to mlazzaro, Hod...@writeme.com, Luke Palmer, perl6-l...@perl.org
Sorry if I say anything dumb - I'm not as good as Perl as you guys... But
for what my thoughts are worth....

> Paul wrote:
> > > So autoconversion of types, if done too liberally, pretty much
> > > evaporates strong typing entirely. That's my worry -- how to get the
> > > wonderousness of what we mean, without letting the compiler get
> > > carried away.
> >
> > Unless the lightbulb I'm seeing in my head is high blood pressure,
> >
> > no strict types;
> >
> > gives you magical autoconversions, and
> >
> > use strict types;
> >
> > gives you magical type enforcement.
>
> Yes, perhaps, but I still have the nagging suspicion that there's quite
> a range of desirable behavior that lies somewhere between
> all-coercions-on and all-coercions-off.
>
> There are some types that _should_ always autocoerce.(?) C<int> to/from
> C<Int>, for example. C<int> to C<num>, but not C<num> to C<int>;
> C<int> to C<str>, obviously. And it'd be great if you could
> specifically tell your Foo obj that it was always allowed to coerce to a
> Baz object, if need be, independant of the more global 'strictness'
> setting. And it'd be greater if, assuming a Baz could be coerced to a
> Bar, the compiler then knew it could turn a Foo into a Bar by "chaining"
> the coercions through Baz.

I agree with what you're getting at, though I think that "no strict types"
and "use strict types" should fulfil their roles in a full sense, and we
should be able to define what we want to allow to "autocoerce" seperately.
I certainly would appreciate type checking, but it would also be nice to
know that I could get away with doing certain assignments where there is no
possibility for loss of meaning through coercion without having to do
something special to make the coercion happen.

I think that someone suggested that you could specify what happened by
defining how to and from coercions take place between different types by
using "to" and "from" syntax in a class (coercion methods?) If these are
there, and "use strict types" was in place, I presume it would ignore these
and not allow the coercion unless you specifically asked for it?

What if we were to be able to say "use strict coercions". This would mean
that only types of object that had methods for coercion explcitly defined
would be allowed to "autocoerce". Of course, this begs the quesiton of how
we define what coercion is allowed for built in types. Extending the
classes of these built in types (if you can - sorry if I've just made a
stupid comment) by adding your own coercion methods seems a bit silly if
you're likely to want to do it regularly. There is probably a better way.

> But my point with the "nearly everything can convert to and from
> strings" example is that if we were to allow the "chaining" of
> coercions, I think the compiler would *always* find a (very wrong) way
> to coerce between any two types/classes, rendering the types absolutely
> useless. Just 'cause a Foo can be turned into a string, and a Baz can
> be obtained _from_ a string, doesn't mean that a Foo can be made into a
> Baz. Thus, "chaining" in particular would appear to be nearly
> impossible to get to behave correctly.(?) But I would dearly love to be
> wrong about that.

Maybe you could do a "shortest route" method and weight coercion to a string
more heavily than a built in coercion method or disallow it? Under my "use
strict coercions" pragma idea you could possibly say that stringification
only happens if a to Str "coercion method" was defined for it.

> But these are just half-thoughts... dunno, I need to percolate these a
> while. But do you see my concern, that I want a happy medium between
> "always coerce" and "never coerce"?

I see your concern and while my suggestion probably gets a big red X next to
it, at least you know someone agrees. ;-)

Take care y'all,

Jonathan
--
By knowing a truth we can always create a fallacy, but knowing a fallacy
never enables us to determine a truth. If it did, we'd have all the answers
by now.

Paul

unread,
Apr 20, 2003, 10:09:14 PM4/20/03
to Jonathan Worthington, mlazzaro, Luke Palmer, perl6-l...@perl.org

--- Jonathan Worthington <jona...@jwcs.net> wrote:
> Sorry if I say anything dumb - I'm not as good as Perl as you guys...
> But for what my thoughts are worth....

lol -- hey, I've never written a program yet in Perl 6 that failed to
run *exactly* the way I wanted it to on the very first try....

mostly because I've never written a program yet in Perl 6. :)

Maybe a way to predeclare?

use strict allow => { Int => Str, Foo => Bar };


> I think that someone suggested that you could specify what happened
> by defining how to and from coercions take place between different
> types by using "to" and "from" syntax in a class (coercion methods?)
> If these are there, and "use strict types" was in place, I presume
> it would ignore these and not allow the coercion unless you
> specifically asked for it?

Which means the classes would clarify everything you intended to allow
internally, so *those* things would be ok, like it should be ok to
assign an Int to a Num. Right?



> What if we were to be able to say "use strict coercions". This would
> mean that only types of object that had methods for coercion
explcitly
> defined would be allowed to "autocoerce". Of course, this begs the
> quesiton of how we define what coercion is allowed for built in
types.

I'd vote for that to me the default, at least under strict. Maybe
"coersions" is a subset of the strictures specified by "types"?

> Extending the classes of these built in types (if you can - sorry if
> I've just made a stupid comment) by adding your own coercion methods
> seems a bit silly if you're likely to want to do it regularly.

Not if you need something they don't already provide. :)

> There is probably a better way.

That's what we're working towards. ;o]

Luke Palmer

unread,
Apr 21, 2003, 12:20:57 AM4/21/03
to jona...@jwcs.net, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org
> > But my point with the "nearly everything can convert to and from
> > strings" example is that if we were to allow the "chaining" of
> > coercions, I think the compiler would *always* find a (very wrong) way
> > to coerce between any two types/classes, rendering the types absolutely
> > useless. Just 'cause a Foo can be turned into a string, and a Baz can
> > be obtained _from_ a string, doesn't mean that a Foo can be made into a
> > Baz. Thus, "chaining" in particular would appear to be nearly
> > impossible to get to behave correctly.(?) But I would dearly love to be
> > wrong about that.
> Maybe you could do a "shortest route" method and weight coercion to a string
> more heavily than a built in coercion method or disallow it?

Er, certainly not. I do hope you see why. (The complexity that
ensues from an I<unweighted> shortest path is already too much)

> Under my "use strict coercions" pragma idea you could possibly say
> that stringification only happens if a to Str "coercion method" was
> defined for it.

That's the problem. Everyone wants to define a to Str coercion method
for their class, for serialization purposes.

Or under Damian's example, everyone wants to define a MyClass <=> Str
multi.

In this case, I think making a distinction between serialization and
coersion would make a big difference. That or not allowing coersion
chains. Or doing something Just Right in the middle.

Luke

Jonathan Worthington

unread,
Apr 21, 2003, 6:48:41 AM4/21/03
to Hod...@writeme.com, mlazzaro, Luke Palmer, perl6-l...@perl.org
> > Sorry if I say anything dumb - I'm not as good as Perl as you guys...
> > But for what my thoughts are worth....
>
> lol -- hey, I've never written a program yet in Perl 6 that failed to
> run *exactly* the way I wanted it to on the very first try....
>
> mostly because I've never written a program yet in Perl 6. :)
<chuckles> Neither have I, but I look forward to it. :)

I was kind of thinking about something a bit like that, but couldn't think
of a nice way to put it syntactically. I'm not sure that suggestion would
work, because imagine if I said:-

use strict allow => { Int => Str, Int => Num, Foo => Bar };

To me it looks like "allow" is becoming a reference to an anonymous hash,
but we have a problem in that example because we would have two enteries for
Int. By my understanding, that means that the second would replace the
first (that's how we define defaults and allow them to be over-ridden in
constructors). I'd suggest if so it's not a good idea to make => work
differently just because of the situation it's in. I know we could possibly
work around it by flattening that to an @array (as => is just a fancy comma)
and then using the data to construct some other kind of allowed coercions
"table". Or is all this just the way I'm looking at it from a Perl 5 point
of view and getting it mixed up?

Are we allowed to call methods on pragmatic modules (if not, excuse my
ignorance):

strict.allow (Int, Str); #That's a better indication of how it really
works...
strict.allow (Int => Str); #But if you flatten that I expect it mean the
same, but look nice to some?

That seems slightly better as it won't suffer from the above problem if you
only specify one coercion at a time, but then you have to type strict.allow
a heck of a lot if you've got a lot of coercions that you wish to allow! So
I don't really think that's a good method either.

> > I think that someone suggested that you could specify what happened
> > by defining how to and from coercions take place between different
> > types by using "to" and "from" syntax in a class (coercion methods?)
> > If these are there, and "use strict types" was in place, I presume
> > it would ignore these and not allow the coercion unless you
> > specifically asked for it?
>
> Which means the classes would clarify everything you intended to allow
> internally, so *those* things would be ok, like it should be ok to
> assign an Int to a Num. Right?

Unless I'm missing what you mean, I thought "use strict types" would not
allow any automatic coercion to take place, even if the method was defined
for it. You could explicitly have to say "I want you to coerce here" when
doing an assignment involving different types. Maybe I've got that wrong.
Then "use strict coercions" would only allow automatic coercion where a
method for that to happen had been defined. It wouldn't try to invent a
method to do it. (Though that does raise the chaining debate, where it
kinda has to invent a way by going through the defined coercion methods of
other types).

> > What if we were to be able to say "use strict coercions". This would
> > mean that only types of object that had methods for coercion
> explcitly
> > defined would be allowed to "autocoerce". Of course, this begs the
> > quesiton of how we define what coercion is allowed for built in
> types.
>
> I'd vote for that to me the default, at least under strict. Maybe
> "coersions" is a subset of the strictures specified by "types"?

Yes, I did wonder whether it should be more like "use strict type coercions"
so we left the word type in there, but that is getting a bit wordy. Plus it
says "type" rather than "types", so it's not perfect... ;-)

> > Extending the classes of these built in types (if you can - sorry if
> > I've just made a stupid comment) by adding your own coercion methods
> > seems a bit silly if you're likely to want to do it regularly.
>
> Not if you need something they don't already provide. :)

True...but what I meant is would you want to explicitly define you wanted
Int to Num, or int to str, etc etc. in every script you created if those
coercions are ones you said should always take place automatically? ("There


are some types that _should_ always autocoerce.(?) C<int> to/from C<Int>,
for example. C<int> to C<num>, but not C<num> to C<int>; C<int> to C<str>,

obviously.")

> > There is probably a better way.
>
> That's what we're working towards. ;o]

I'm sure we'll get there one day. :-)

Jonathan


Jonathan Worthington

unread,
Apr 21, 2003, 7:04:57 AM4/21/03
to Luke Palmer, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org
> > > But my point with the "nearly everything can convert to and from
> > > strings" example is that if we were to allow the "chaining" of
> > > coercions, I think the compiler would *always* find a (very wrong) way
> > > to coerce between any two types/classes, rendering the types
absolutely
> > > useless. Just 'cause a Foo can be turned into a string, and a Baz can
> > > be obtained _from_ a string, doesn't mean that a Foo can be made into
a
> > > Baz. Thus, "chaining" in particular would appear to be nearly
> > > impossible to get to behave correctly.(?) But I would dearly love to
be
> > > wrong about that.
> > Maybe you could do a "shortest route" method and weight coercion to a
string
> > more heavily than a built in coercion method or disallow it?
>
> Er, certainly not. I do hope you see why. (The complexity that
> ensues from an I<unweighted> shortest path is already too much)
Ouch...yes, now I see the light.

> > Under my "use strict coercions" pragma idea you could possibly say
> > that stringification only happens if a to Str "coercion method" was
> > defined for it.
>
> That's the problem. Everyone wants to define a to Str coercion method
> for their class, for serialization purposes.
>
> Or under Damian's example, everyone wants to define a MyClass <=> Str
> multi.
>
> In this case, I think making a distinction between serialization and
> coersion would make a big difference. That or not allowing coersion
> chains. Or doing something Just Right in the middle.

Damian suggested something that looked like this:-

multi COERCE (Bar $from) returns Foo {...}

Which I like much better than the to/from proposals that were floating
around as we don't need to add to and from "constructs" (or were they
already there?), we can use multi which we had already.

I guess you could specify serialization seperately by writing it like this:-

multi SERIALIZE (Bar $from) returns Str {...}

However, that means that someone could potentialy specify a different method

to take place in coercion to an Str and serialization. I'm not sure if that
would be useful or just a bad idea generally, though I'm sure somebody will
enlighten me either way. ;-)

Jonathan


Damian Conway

unread,
Apr 21, 2003, 8:54:27 AM4/21/03
to perl6-l...@perl.org
Jonathan Worthington wrote:

> I guess you could specify serialization seperately by writing it like this:-
>
> multi SERIALIZE (Bar $from) returns Str {...}
>
> However, that means that someone could potentialy specify a different method

No. Only one C<multi> of a given signature is allowed. So anyone else
specifying the same thing would get at least a warning.

Of course, as in Perl 5, in Perl 6 you can rebind just about anything at any
time, or temporize it, or shadow it with a lexical. So respecification of such
conversion mechanisms will always be a very real possibility.

However...unlike coercion, serialization *is* a property of a single class
(the Str class has very little to do with the actual process of
serialization), so I suspect we'll have serialization methods, rather than
multimethods.

Damian

Sean O'Rourke

unread,
Apr 21, 2003, 9:05:42 AM4/21/03
to Luke Palmer, jona...@jwcs.net, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org
On 20 Apr 2003, Luke Palmer wrote:
> > Maybe you could do a "shortest route" method and weight coercion to a
> > string more heavily than a built in coercion method or disallow it?
>
> Er, certainly not. I do hope you see why. (The complexity that
> ensues from an I<unweighted> shortest path is already too much)

I'll bite. First, I think the costs of weighted and unweighted conversion
search would be the same no matter what you do -- how is their being
unweighted a win? Second, what's "too expensive" here? You can either
use Dijkstra's algorithm to find a single type's shortest conversion in
O(N log N + M), or Floyd-Warshall to find them all in O(N^3) (where N is
the number of types, and M is the number of conversions). That looks
expensive, but... If defining type conversions is much less common than
using them, then you can avoid this much of the time by caching the
results. (Just don't let people define conversion multimethods with
AUTOLOAD ;). And if you limit the maximum cost of conversions, then
neither algorithm will be as expensive as its big-O time suggests, since
you can give up after reaching that limit.

/s

Paul

unread,
Apr 21, 2003, 10:42:29 AM4/21/03
to Jonathan Worthington, mlazzaro, Luke Palmer, perl6-l...@perl.org
> > Maybe a way to predeclare?
> >
> > use strict allow => { Int => Str, Foo => Bar };
>
> I was kind of thinking about something a bit like that, but
> couldn't think of a nice way to put it syntactically. I'm
> not sure that suggestion would work, because imagine if I said:-
>
> use strict allow => { Int => Str, Int => Num, Foo => Bar };
>
> To me it looks like "allow" is becoming a reference to an anonymous
> hash, but we have a problem in that example because we would have
> two enteries for Int. By my understanding, that means that the
> second would replace the first (that's how we define defaults and
> allow them to be over-ridden in constructors).

Ah, good point. Wasn't thinking that far ahead.

> I'd suggest if so it's not a good idea to make => work
> differently just because of the situation it's in.

LOL!! Absolutely!

> I know we could possibly work around it by flattening that to
> an @array (as => is just a fancy comma) and then using the data
> to construct some other kind of allowed coercions "table". Or
> is all this just the way I'm looking at it from a Perl 5 point
> of view and getting it mixed up?

I dunno. When I saw what you were saying I did wrong, my first thought
was just to ammend it to

use strict allow => [ Int => Str, Int => Num, Foo => Bar ];

I'd still say that was a touch kludgy, but now that => is actually the
pair constructor, the strict module could literally just stuff the pair
into a hash as a lookup key, and in a context that it needed to check
for coersions could build a quick string pair of type names and check
the table.

The other problem I saw was that a lot of those are just barewords....

> Are we allowed to call methods on pragmatic modules (if not, excuse
> my ignorance):
>

> strict.allow(Int, Str); #better indication of how it really works...

Not necessarily -- => is a pair constructor now, not just "fat comma".

> strict.allow(Int => Str);

> #But if you flatten that I expect it mean the same,

> # but look nice to some?

Again, doesn't mean the same, and I do think it's clearer; it uses the
pointiness of => to indicate the direction of the coersion, without
having to add any special ectra syntax. :)

> That seems slightly better as it won't suffer from the above problem
> if you only specify one coercion at a time, but then you have to type
> strict.allow a heck of a lot if you've got a lot of coercions that
> you wish to allow! So I don't really think that's a good method
> either.

But you *could* say

strict.allow(Int => Str, Num => Str);

> > [...]


> Unless I'm missing what you mean, I thought "use strict types" would
> not allow any automatic coercion to take place, even if the method
> was defined for it. You could explicitly have to say "I want you to
> coerce here" when doing an assignment involving different types.
> Maybe I've got that wrong.

Several folk are still fuzzy on that, and I'm one.
More to the point, various folk have different preferences on that,
which is what fuels a lot of this discussion.

I could see the usefulness of shades of gray here, but am inclined to
implement them by turning stricture on and off manually. I'd vote not
to bloat the system, and if you want stricture, it should be strict.
When you don't want stricture, turn it off, and do it explicitly so
that any reader of code knows what you meant.

> Then "use strict coercions" would only allow automatic coercion where
> a method for that to happen had been defined. It wouldn't try to
> invent a method to do it. (Though that does raise the chaining
> debate, where it kinda has to invent a way by going through the
> defined coercion methods of other types).

So you suggest "coercions" as an *addition* to "types", instead of a
replacement? Ok, I could see that. Again, I vote for streamlining, even
though it means more lines of code for me, but I'm flexible.

> > > Extending the classes of these built in types (if you can
> > > - sorry if I've just made a stupid comment) by adding your
> > > own coercion methods seems a bit silly if you're likely to
> > > want to do it regularly.
> >
> > Not if you need something they don't already provide. :)
>
> True...but what I meant is would you want to explicitly define
> you wanted Int to Num, or int to str, etc etc. in every script
> you created if those coercions are ones you said should always
> take place automatically? ("There are some types that _should_
> always autocoerce.(?) C<int> to/from C<Int>, for example.
> C<int> to C<num>, but not C<num> to C<int>; C<int> to C<str>,
> obviously.")

I suspect the design team will make it DRTR, or at least DWIM.
Even so, I could see arguments for even those conversions to be tabu.
I think that might be going overboard, but I still say strict should
mean strict.

Michael Lazzaro

unread,
Apr 21, 2003, 12:57:38 PM4/21/03
to Luke Palmer, dam...@conway.org, perl6-l...@perl.org
On Sunday, April 20, 2003, at 09:20 PM, Luke Palmer wrote:
>>> But my point with the "nearly everything can convert to and from
>>> strings" example is that if we were to allow the "chaining" of
>>> coercions, I think the compiler would *always* find a (very wrong)
>>> way
>>> to coerce between any two types/classes, rendering the types
>>> absolutely
>>> useless. Just 'cause a Foo can be turned into a string, and a Baz
>>> can
>>> be obtained _from_ a string, doesn't mean that a Foo can be made
>>> into a
>>> Baz. Thus, "chaining" in particular would appear to be nearly
>>> impossible to get to behave correctly.(?) But I would dearly love
>>> to be
>>> wrong about that.
<snip>

> That's the problem. Everyone wants to define a to Str coercion method
> for their class, for serialization purposes.
<snip>

> In this case, I think making a distinction between serialization and
> coersion would make a big difference. That or not allowing coersion
> chains. Or doing something Just Right in the middle.

Hmm. An idea is forming, here...

The problem with string serialization, as we've discussed before, is
that it's frighteningly unspecific. We argue about whether the
serialization of an object should look more "debugger-friendly" or more
"output-friendly", since we can't have both. We frequently want to be
able to deserialize an object from a string, but any given object could
have *multiple* string formats that it can use; comma-delimited,
Storable, XML, etc.

This is just crude, but what if we did something to the effect
"coercing to streams". For example:

multi COERCE (Foo $foo, STDOUT $out) returns str {...}
multi COERCE (Foo $foo, STDERR $out) returns str {...}

So that:

print $foo;
print STDERR: $foo;

could, indeed, print two different things, depending on the _type_
associated with each stream.

The point behind this would be that you would never define coercions to
and from str format, directly, so you would never have the nasty
chaining-coercion problems. Instead, you'd be defining coercions to
output 'types', which would _never_ have cooresponding
reverse-coercions... they're one-way.

OK, maybe that's not quite there yet. Perhaps it's more like this:
C<Str> is a base class, from which more specific 'serialization'
classes arise:

class Str {...}
class StrOut is Str {...} # or is this one even needed?
class StrErr is Str {...}
class StrXML is Str {...}
class StrDelimited is Str {...}

So instead of serializing/coercing "to a string", you're
serializing/coercing "to a format which happens to be based on string".
You need to attach the correct type of serialization to whatever I/O
source you're dealing with; by default, STDERR would use StrErr, but
STDOUT and other pipes would default to plain C<Str>.

(Note this ties into the stuff about regexes working on things other
than strings, too. And solves the argument over 'how debuggy' to make
the stringification of hashes, etc. And maybe means that interpolated
strings are _lazily_ interpolated, depending on the context in which
they are used.)

Hmm...

MikeL

Michael Lazzaro

unread,
Apr 21, 2003, 1:12:51 PM4/21/03
to perl6-l...@perl.org

A follow-up... more specifically, how it would solve our problems, and
fixing that dumbass syntax issue I botched in the last message.
Suppose you had a class that you attached a bunch of _output_ coercions
to:

class Foo {...}

multi COERCE( Foo $f ) returns str {...}
multi COERCE( Foo $f ) returns StrErr {...}
multi COERCE( Foo $f ) returns StrXML {...}

That says that, by default, it'll coerce to string in a particular way.
But if you're coercing to a debugging string, or an XML string, it
will choose alternate approaches.

You can then put:

multi COERCE( StrXML $s ) returns Foo {...}

... and you have the reverse-coercion, e.g. instanciating the object
from an XML string. But you still don't have the "autocoerce flakes
out because it's finding a path through str", because you don't _have_
a reverse path to str... it's a one-way trip. That's how you solve the
problem... you don't define constructors _from_ Str, you define
constructors from _subclasses_ of Str.

However, if your particular class was such that the coercion to and
from raw C<str> was not lossy; e.g.

class PersonName {...} # a name, with some other methods attached

multi COERCE( PersonName $name ) returns str {...};
multi COERCE( str $s ) returns PersonName {...}

... you _could_ have it coerce both ways, and it'd even be correct to
do so, and in fact you'd WANT it to do that. Alternatively, you could
say:

class PersonName is Str {...}

but maybe you didn't want to do that, for some reason. So you can base
your object on whatever you want, and use the coercions; TMTOWTDI.

OK, I'm beginning to like this approach quite a lot...

MikeL

Michael Lazzaro

unread,
Apr 21, 2003, 1:22:05 PM4/21/03
to Michael Lazzaro, perl6-l...@perl.org

On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
> A follow-up...

One more. :-P

But it doesn't solve this problem, directly:

class Foo {...}
class Bar {...} # unrelated

multi COERCE( Foo $f ) returns StrXML {...}

multi COERCE( StrXML $s ) returns Bar {...}

e.g., it still thinks it can turn a Foo into a Bar by coercing through
StrXML. Doh!

So, indeed, it may be that things like Str, StrXML, etc., are
specifically marked as "SERIALIZE", not "COERCE", and that magic
autocoercion doesn't use serialization.

Thus

-- coercions chain magically, but...
-- serializations don't interact with coercions
-- stringification is more globally extended to represent serialization
in general, with the specific serialization done dependent on the
subclass of Str being created.

Sorry 'bout that, but mah thinkin' hatz on.

MikeL

Paul

unread,
Apr 21, 2003, 1:34:06 PM4/21/03
to Michael Lazzaro, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
> On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
> > A follow-up...
>
> One more. :-P

lol -- hey, man, that's why I subscribed! ;o]

> But it doesn't solve this problem, directly:
> class Foo {...}
> class Bar {...} # unrelated
> multi COERCE( Foo $f ) returns StrXML {...}
> multi COERCE( StrXML $s ) returns Bar {...}
>
> e.g., it still thinks it can turn a Foo into a Bar by coercing
> through StrXML. Doh!
> So, indeed, it may be that things like Str, StrXML, etc., are
> specifically marked as "SERIALIZE", not "COERCE", and that magic
> autocoercion doesn't use serialization.
> Thus
> -- coercions chain magically, but...
> -- serializations don't interact with coercions
> -- stringification is more globally extended to represent
> serialization
> in general, with the specific serialization done dependent on the
> subclass of Str being created.

Sweet. Would there be a way to

> Sorry 'bout that, but mah thinkin' hatz on.
>
> MikeL
>

Paul

unread,
Apr 21, 2003, 1:34:05 PM4/21/03
to Michael Lazzaro, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
> On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
> > A follow-up...
>
> One more. :-P

lol -- hey, man, that's why I subscribed! ;o]

> But it doesn't solve this problem, directly:


> class Foo {...}
> class Bar {...} # unrelated
> multi COERCE( Foo $f ) returns StrXML {...}
> multi COERCE( StrXML $s ) returns Bar {...}
>
> e.g., it still thinks it can turn a Foo into a Bar by coercing
> through StrXML. Doh!
> So, indeed, it may be that things like Str, StrXML, etc., are
> specifically marked as "SERIALIZE", not "COERCE", and that magic
> autocoercion doesn't use serialization.
> Thus
> -- coercions chain magically, but...
> -- serializations don't interact with coercions
> -- stringification is more globally extended to represent
> serialization
> in general, with the specific serialization done dependent on the
> subclass of Str being created.

Sweet. Would there be a way to

> Sorry 'bout that, but mah thinkin' hatz on.
>
> MikeL
>


Paul

unread,
Apr 21, 2003, 1:35:15 PM4/21/03
to Michael Lazzaro, perl6-l...@perl.org

Sorry folks.
I started to respond, realized I had nothing of value to add, and
decided not to....then hit the SEND instead of the DELETE.

<shaking head>

Doing penance now. :<

Paul

Luke Palmer

unread,
Apr 21, 2003, 2:48:58 PM4/21/03
to soro...@cs.ucsd.edu, jona...@jwcs.net, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org

Heh, I wasn't talking about algorithmically complex. I meant for the
programmer. Most of the time the programmer wants to know exactly how
the program is going to work, and I don't think there would be
anything resembling black magic more than a weighted coersion search.

Thanks for discussing the algorithms, though. :)

Luke

Paul

unread,
Apr 21, 2003, 2:52:09 PM4/21/03
to Luke Palmer, soro...@cs.ucsd.edu, jona...@jwcs.net, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org
> Heh, I wasn't talking about algorithmically complex. I meant for the
> programmer. Most of the time the programmer wants to know exactly
> how the program is going to work, and I don't think there would be
> anything resembling black magic more than a weighted coersion search.

lol -- yeah. Real transparency of design.
I don't think I want a fuzzy-logic compiler.....

Luke Palmer

unread,
Apr 21, 2003, 2:54:22 PM4/21/03
to Hod...@writeme.com, jona...@jwcs.net, mlaz...@cognitivity.com, perl6-l...@perl.org
> > > Maybe a way to predeclare?
> > >
> > > use strict allow => { Int => Str, Foo => Bar };
> >
> > I was kind of thinking about something a bit like that, but
> > couldn't think of a nice way to put it syntactically. I'm
> > not sure that suggestion would work, because imagine if I said:-
> >
> > use strict allow => { Int => Str, Int => Num, Foo => Bar };
> >
> > To me it looks like "allow" is becoming a reference to an anonymous
> > hash, but we have a problem in that example because we would have
> > two enteries for Int. By my understanding, that means that the
> > second would replace the first (that's how we define defaults and
> > allow them to be over-ridden in constructors).
>
> Ah, good point. Wasn't thinking that far ahead.

It might just work if that hash constructor is in MultiMap context or
somesuch. :)

> > I'd suggest if so it's not a good idea to make => work
> > differently just because of the situation it's in.
>
> LOL!! Absolutely!

That's precisely what context does.

> > I know we could possibly work around it by flattening that to
> > an @array (as => is just a fancy comma) and then using the data
> > to construct some other kind of allowed coercions "table". Or
> > is all this just the way I'm looking at it from a Perl 5 point
> > of view and getting it mixed up?
>
> I dunno. When I saw what you were saying I did wrong, my first thought
> was just to ammend it to
>
> use strict allow => [ Int => Str, Int => Num, Foo => Bar ];
>
> I'd still say that was a touch kludgy, but now that => is actually the
> pair constructor, the strict module could literally just stuff the pair
> into a hash as a lookup key, and in a context that it needed to check
> for coersions could build a quick string pair of type names and check
> the table.
>
> The other problem I saw was that a lot of those are just barewords....

No, they're types. Types are real types in Perl 6, they're not just
strings. So that compiles no matter how strict you ask the compiler
to be.

Luke

Paul

unread,
Apr 21, 2003, 3:34:25 PM4/21/03
to perl6-l...@perl.org
--- Luke Palmer <fibo...@babylonia.flatirons.org> wrote:
> > > use strict allow => { Int => Str, Int => Num, Foo => Bar };
>
> It might just work if that hash constructor is in MultiMap context or
> somesuch. :)

?? Please provide elaboration or a reference where I can cure my
ignorance on this topic. :)

> > The other problem I saw was that a lot of those are just
> > barewords....
>
> No, they're types. Types are real types in Perl 6, they're not just
> strings. So that compiles no matter how strict you ask the compiler
> to be.

Sweet, but confusing. Easy enough to handle, tho...
If I want it as a string, just quote it. :)

Luke Palmer

unread,
Apr 21, 2003, 4:16:32 PM4/21/03
to Hod...@writeme.com, perl6-l...@perl.org
> --- Luke Palmer <fibo...@babylonia.flatirons.org> wrote:
> > > > use strict allow => { Int => Str, Int => Num, Foo => Bar };
> >
> > It might just work if that hash constructor is in MultiMap context or
> > somesuch. :)
>
> ?? Please provide elaboration or a reference where I can cure my
> ignorance on this topic. :)

A6 has some things to say about context, like how lists flatten
themselves in List context, etc. In essence, things behave
differently in different contexts. If there were a MultiMap context,
it might overload the {} constructor. Then it could do whatever it
liked to the list of pairs, like, say, allowing multiple pairs with
the same key.

This is speculative, in that I have no idea whether contexts are
allowed to overload things like the hash constructor. I just hope
they are.

> > > The other problem I saw was that a lot of those are just
> > > barewords....
> >
> > No, they're types. Types are real types in Perl 6, they're not just
> > strings. So that compiles no matter how strict you ask the compiler
> > to be.
>
> Sweet, but confusing. Easy enough to handle, tho...
> If I want it as a string, just quote it. :)

Or put it on the left side of a pair constructor or a hash subscript
when they're expecting strings, which is the default.

Luke

Sean O'Rourke

unread,
Apr 21, 2003, 4:24:15 PM4/21/03
to Luke Palmer, perl6-l...@perl.org
On 21 Apr 2003, Luke Palmer wrote:
> Heh, I wasn't talking about algorithmically complex. I meant for the
> programmer. Most of the time the programmer wants to know exactly how
> the program is going to work, and I don't think there would be
> anything resembling black magic more than a weighted coersion search.

I'd like to nominate (1) multimethod resolution, (2) method search with
multiple inheritance (especially with user-definable rules for resolving
conflicts), and (3) anything involving AUTOLOAD. (And for the prolog fans
out there, I'll note that sometimes it's good _not_ to know exactly how
the program is going to work...)

You're right that search through a weighted graph might be a bit too
general, but I think that a limited form of it would be unproblematic.
Define some conversions as lossless, and others as lossy, then allow
conversion if there is a sequence of lossless conversions between one type
and another. Since the conversions lose no information, the only reason
to choose one path over another is efficiency -- any possible conversion
path will yield exactly the same result. So the weights represent
computational cost rather than information loss.

If lossy conversions are required, then only a single step is allowed
unless the user spells out the steps explicitly. Conversions to string,
for example, could be specified as lossy, meaning that objects would
stringify and unstringify automatically, but conversions between types
could not go through String.

/s

Paul

unread,
Apr 21, 2003, 4:28:32 PM4/21/03
to Luke Palmer, perl6-l...@perl.org
> > > > > use strict allow => { Int => Str, Int => Num, Foo => Bar };
> > >
> > > It might just work if that hash constructor is in MultiMap
> > > context or somesuch. :)
> >
> > ?? Please provide elaboration or a reference where I can cure my
> > ignorance on this topic. :)
>
> A6 has some things to say about context, like how lists flatten
> themselves in List context, etc. In essence, things behave
> differently in different contexts. If there were a MultiMap context,
> it might overload the {} constructor. Then it could do whatever it
> liked to the list of pairs, like, say, allowing multiple pairs with
> the same key.
>
> This is speculative, in that I have no idea whether contexts are
> allowed to overload things like the hash constructor. I just hope
> they are.

Oh, then I misunderstood what you meant. I thought therewas already a
P6 MultiMap document somewhere. :)

> > > > The other problem I saw was that a lot of those are just
> > > > barewords....
> > >
> > > No, they're types. Types are real types in Perl 6, they're not
> > > just strings. So that compiles no matter how strict you ask the
> > > compiler to be.
> >
> > Sweet, but confusing. Easy enough to handle, tho...
> > If I want it as a string, just quote it. :)
>
> Or put it on the left side of a pair constructor or a hash subscript
> when they're expecting strings, which is the default.

Like I said, just quote it, lol....

Maybe by default the "allow" in

use strict types, allow => [ Int => Str, Int => Num ];

would take the list of pair objects and assign them as keys in a lookup
hash %strict::allow with some boolean true value, so that for context

my Int $x = Str.new;

it could

die "stupid!" unless %strict::allow{ Int => Str };

Ok, maybe it could offer a little more useful info. :op

Jonathan Worthington

unread,
Apr 21, 2003, 4:40:14 PM4/21/03
to soro...@cs.ucsd.edu, Luke Palmer, mlaz...@cognitivity.com, Hod...@writeme.com, perl6-l...@perl.org
Nice bite Sean, though I can see both sides of the argument clearly. If
serialization was seperated out from coercion then I guess the weighting
wouldn't be needed. Beyond that, a "shortest path" doesn't seem so much
like black magic to me - at least then the docs can say "it finds the method
of coercion that will take the shortest number of steps" and that's a fairly
clean explanation.

I guess if we wanted to keep it consistent you could use a similar approach
to inheritence search through @ISA that takes place when looking for a
method from a /(?:great)*(?:grand)?parent/ (or /[great]* [grand]? parent/ in
Perl6? ;-)) class....if that'd work in this situation.

Jonathan

Mark Biggar

unread,
Apr 21, 2003, 2:58:11 PM4/21/03
to Michael Lazzaro, perl6-l...@perl.org
Michael Lazzaro wrote:
>
> On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
>
>> A follow-up...
>
>
> One more. :-P
>
> But it doesn't solve this problem, directly:
>
> class Foo {...}
> class Bar {...} # unrelated
>
> multi COERCE( Foo $f ) returns StrXML {...}
> multi COERCE( StrXML $s ) returns Bar {...}
>
> e.g., it still thinks it can turn a Foo into a Bar by coercing through
> StrXML. Doh!

Actually this case is not a bad is it looks because the COERCE from
StrXML to Bar will likely throw a runtime exception if the XML
string is gets doesn't look like /\<Bar>.*?/.


--
Mark Biggar
ma...@biggar.org
mark.a...@attbi.com

Mark Biggar

unread,
Apr 21, 2003, 6:53:57 PM4/21/03
to perl6-l...@perl.org
Michael Lazzaro wrote:
>
> On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
>
>> A follow-up...
>
>
> One more. :-P
>
> But it doesn't solve this problem, directly:
>
> class Foo {...}
> class Bar {...} # unrelated
>
> multi COERCE( Foo $f ) returns StrXML {...}
> multi COERCE( StrXML $s ) returns Bar {...}
>
> e.g., it still thinks it can turn a Foo into a Bar by coercing through
> StrXML. Doh!

Actually this case is not a bad is it looks because the COERCE from

Mark Biggar

unread,
Apr 22, 2003, 2:45:56 AM4/22/03
to perl6-l...@perl.org
Michael Lazzaro wrote:
>
> On Monday, April 21, 2003, at 10:12 AM, Michael Lazzaro wrote:
>
>> A follow-up...
>
>
> One more. :-P
>
> But it doesn't solve this problem, directly:
>
> class Foo {...}
> class Bar {...} # unrelated
>
> multi COERCE( Foo $f ) returns StrXML {...}
> multi COERCE( StrXML $s ) returns Bar {...}
>
> e.g., it still thinks it can turn a Foo into a Bar by coercing through
> StrXML. Doh!

Actually this case is not a bad is it looks because the COERCE from

Austin Hastings

unread,
Apr 22, 2003, 10:20:32 AM4/22/03
to Mark Biggar, perl6-l...@perl.org

Actually it's worse than it looks if you consider that "lossy" (and/or
"lose-y") conversion paths may mask longer-but-valid correct paths.

In many cases the answer is "Don't structure your classes that way."
But I think the concensus here is that the issue of (auto)conversion
needs to be separated from serialization and friends.

=Austin

Michael Lazzaro

unread,
Apr 22, 2003, 12:48:50 PM4/22/03
to Austin_...@yahoo.com, Mark Biggar, perl6-l...@perl.org

Now, when I was writing that, I was 90% convinced that doing something
such that you had different subclasses of string in which objects could
"stringify" different ways would, in fact, solve the problem. But
apparently the margins of my brain were too small to contain it, and it
got away.

One question I have is when to define something as a "serialization"
vs. a "coercion". It seems obvious at first glance, but pretty much
all serializations can be thought of as coercions, and some coercions
can be thought of as serializations. Should we simply define it as
"coercions chain, serializations don't"?

Another question I have, looking back, is why we're considering
coercion chains to be important at all. Do they really come up that
often, I wonder, or does class inheritance take care of the vast
majority of these cases? Or are we confusing the issue with generic
programming?

MikeL

Luke Palmer

unread,
Apr 22, 2003, 12:55:07 PM4/22/03
to mlaz...@cognitivity.com, Austin_...@yahoo.com, ma...@biggar.org, perl6-l...@perl.org
> Another question I have, looking back, is why we're considering
> coercion chains to be important at all. Do they really come up that
> often, I wonder, or does class inheritance take care of the vast
> majority of these cases? Or are we confusing the issue with generic
> programming?

As I've said, chaining coercions doesn't come up so often in everyday,
straightforward programming. They do, however, allow you to do some
very clever things. I don't know whether these clever things would be
easy to do a different way in Perl (likely they would be). But to
demonstrate the point, if C++ allowed chained coercions, I would have
a run-time extensible logarithmic double dispatcher now.

(It was really disappointing. Hey, I've got it! And then... darn, it
only allows one.)

Coercions are important for delegation, if there is no other means by
which this can be done. I get the impression that Perl 6 will
directly support delegation (more directly than AUTOLOAD), so I don't
know whether I can find a common use for chained coercions now. The
dynamic nature of Perl makes them more obfuscatory for solving
problems than needed.

However, it's plausible that they allow a statically typed solution to
a problem that would otherwise only be solved at run-time. I can't
really say.

Luke

Michael Lazzaro

unread,
Apr 22, 2003, 3:29:49 PM4/22/03
to Luke Palmer, Austin_...@yahoo.com, ma...@biggar.org, perl6-l...@perl.org

On Tuesday, April 22, 2003, at 09:55 AM, Luke Palmer wrote:
> Coercions are important for delegation, if there is no other means by
> which this can be done. I get the impression that Perl 6 will
> directly support delegation (more directly than AUTOLOAD), so I don't
> know whether I can find a common use for chained coercions now. The
> dynamic nature of Perl makes them more obfuscatory for solving
> problems than needed.

Yes, that was my halfhearted musing too.

> However, it's plausible that they allow a statically typed solution to
> a problem that would otherwise only be solved at run-time. I can't
> really say.

I wonder how one would best do the following, such that it was enforced
compile-time. Assume you have:

multi diff( str $a, str $b ) returns str {...}
multi diff( StrXML $a, StrXML $b ) returns StrXML {...}
multi diff( StrDelim $a, StrDelim $b ) returns StrDelim {...}

# ...etc...

and that the implementation of those variants were identical; the
_only_ difference between them is you want them to return the same type
as they originally were passed, such that:

my $s = diff($xml1, $xml2);

ref($s); # returns StrXML

But suppose, then, you wanted a "generic" C<diff> that handled any set
of two (identically typed) strings, and spit out an object of that same
type. All the possible types are subclasses of C<Str>, but you don't
want to have to define a variant per subclass, because you want the
function to be useful for any possible subclasses.

It would seem an easy question. Easy answer seems to be to make it a
macro, not a multi, but I'm not sure that's the _best_ answer.

MikeL

Michael Lazzaro

unread,
Apr 22, 2003, 3:53:31 PM4/22/03
to perl6-l...@perl.org

On Tuesday, April 22, 2003, at 12:29 PM, Michael Lazzaro wrote:
> I wonder how one would best do the following, such that it was
> enforced compile-time. Assume you have:
>
> multi diff( str $a, str $b ) returns str {...}
> multi diff( StrXML $a, StrXML $b ) returns StrXML {...}
> multi diff( StrDelim $a, StrDelim $b ) returns StrDelim {...}
>
> # ...etc...

Or, for the simplest possible demonstration of the issue:

class Foo {
method CLONE returns Foo {...}
}

How do you declare CLONE such that it works for all eventual subclasses
of Foo -- returning the correct subclass -- while still retaining the
strict compile-time typing? Such that it wouldn't turn out to be _more
runtime efficient_ to define a CLONE for every class separately, even
if their implementations were identical? [1]

That's the biggie. If that can be credibly solved, a *lot* of things
fall into place.

MikeL

[1] I am quite fed up with having to code Badly in order to get Speed.
Perl5 OO suffers rather significantly from this flummoxacrapicity, as
do plenty of other languages.

Austin Hastings

unread,
Apr 22, 2003, 4:42:19 PM4/22/03
to Michael Lazzaro, perl6-l...@perl.org

--- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
>
> On Tuesday, April 22, 2003, at 12:29 PM, Michael Lazzaro wrote:
> > I wonder how one would best do the following, such that it was
> > enforced compile-time. Assume you have:
> >
> > multi diff( str $a, str $b ) returns str {...}
> > multi diff( StrXML $a, StrXML $b ) returns StrXML {...}
> > multi diff( StrDelim $a, StrDelim $b ) returns StrDelim {...}
> >
> > # ...etc...
>
> Or, for the simplest possible demonstration of the issue:
>
> class Foo {
> method CLONE returns Foo {...}
> }
>
> How do you declare CLONE such that it works for all eventual
> subclasses
> of Foo -- returning the correct subclass -- while still retaining the
>

class Foo {
method CLONE {
my $dolly = new typeof($_);

$dolly.%attributes = %.attributes; # Syntax on .%attr?
return $dolly;

Paul

unread,
Apr 22, 2003, 4:58:39 PM4/22/03
to Austin_...@yahoo.com, Michael Lazzaro, perl6-l...@perl.org
> class Foo {
> method CLONE {
> my $dolly = new typeof($_);
> $dolly.%attributes = %.attributes; # Syntax on .%attr?
> return $dolly;
> }
> }

Hmm....

%$dolly.attributes ?

Not really clear....
umm....that could get ugly. What you've got maybe isn't so bad....

Didn't I see somewhere that the Larry was talking about some DWIMmery
where using an object as a reference in a collection context coerced it
to present the appropriate attribute storage system? so that

%{$dolly} = %.attributes; # ?

That's fairly wierd.... Was I dreaming?
I could see how that would be Big Medicine, but also possibly Bad
Juju...

Arcadi Shehter

unread,
Apr 22, 2003, 5:55:05 PM4/22/03
to Austin_...@yahoo.com, Michael Lazzaro, perl6-l...@perl.org
Austin Hastings writes:
> > >
> > > multi diff( str $a, str $b ) returns str {...}
> > > multi diff( StrXML $a, StrXML $b ) returns StrXML {...}
> > > multi diff( StrDelim $a, StrDelim $b ) returns StrDelim {...}
> > >

it seems that this asks for some autoload - like behaviour happening
at compile time : multi dispatcher will match against "real" patterns
in signatures -- not just "literal" types - or this behaviour exists
already ??

multi diff( ??Type $a, ??Type $b )
returns ??Type {
my ??Type $retval ;
...
return $retval ;
}

where ??Type is placeholder variable for actual type in the called
"diff" sub . and "??" is a placeholder for sigil for such variable .
there was a discussion of such a special sigil in the relation of
this line

my $type $var ;

and there was a notion of yet another sigil for types

my ??type = Int ; # or ... = Type("Int") ????
# or ... = new Type("Int") ????
my ??type $var;

the actual syntax inside the signature may be very different , but the
idea is this -- to have dispatcher to recognize not only "literal"
signatures in which all types are "explicitely" specifyed , but also to
allow it to match against type patterns inside signature , and then
generate ( or if special type variable are allowed - nothing have to
be generated ) the aprpriate body of the sub .

just filtering ( if I understand it correctly ) is not a solution
because I cannot anticipate all possibilities when I write a programm.
This is a point of Michael Lazzaro if I understand it correctly -- I
can generate ( and quite automate this generation ) of many possible
"multi"'s but I want perl to do it - and at compile time - so that
function calls not matching my patterns would be caught at compile
time .

what is desired is that dispatcher at compile time will generate an
apropriate multi ( and dispatch to it ) if I provide it with
apprpriate pattern and instruct it to do so .

anyway , the question is - will ( or should ) the dispatcher of multi
be able to create subs on demand according to some pattern _at compile
time_ .

probably , that question is actually about when and how autoloading
happens in perl6 and how it is related to dispatching .

arcadi .


Piers Cawley

unread,
Apr 28, 2003, 9:34:05 AM4/28/03
to Jonathan Worthington, Hod...@writeme.com, mlazzaro, Luke Palmer, perl6-l...@perl.org
"Jonathan Worthington" <jona...@jwcs.net> writes:

>Paul wrote:
>> Maybe a way to predeclare?
>>
>> use strict allow => { Int => Str, Foo => Bar };
> I was kind of thinking about something a bit like that, but couldn't think
> of a nice way to put it syntactically. I'm not sure that suggestion would

> work, because imagine if I said:-
>
> use strict allow => { Int => Str, Int => Num, Foo => Bar };
>
> To me it looks like "allow" is becoming a reference to an anonymous hash,
> but we have a problem in that example because we would have two enteries for
> Int.

How about:

use strict allow => { Int => Str | Num, Foo => Bar }

But I'm not sure that the example you give is that good, since Int isa
Num anyway so I would be *very* surprised if you weren't allowed to
use an Int where you could use any Num. Of course, the other way
'round:

use strict allow => { Num => Int | Float | Complex | Rational, ... }

makes a good deal more sense.

--
Piers

Paul

unread,
Apr 28, 2003, 9:55:17 AM4/28/03
to Piers Cawley, Jonathan Worthington, mlazzaro, Luke Palmer, perl6-l...@perl.org
> Piers

Yes, but I proposed that initial syntax rather flippantly, more as fuel
for better minds than as an actual frame to be adopted. Hmm....

If we're coint to do this, it's probably better done more like
C<constants> where the pragma is invoked individually for each.

use conversion Num => Int;
use conversion Num => Str;
use conversion Str => Int;
use conversion Str => Num;
use conversion Int => Num;
use conversion Int => Str;
# etc....

On the one hand, that would allow you fine control over which
conversions you wanted to allow, and you'd be able to invoke it in a
lexical context, and expect it (if well written) to go away at the end
of that context, so that you could tweak the bits you wanted more
expicitly.

use strict;
my Str $s = "foo";
my Int $i;
{ use conversion Str => Int;
$i = $s; # okay, assigns zero
}
$i = $s; # blows up

On the other hand, that's a lot of typing....

On the gripping hand (I love aping idionms like that, lol...), it gives
precise control back to the programmer, who can use or not use it as
suits him. If he doesn't want to type so much, he can always drop *ALL*
the way back to plain scalars, or anywhere in between. :)

Which inspires me for a tengential but otherwise unrelated post.....

__________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo.
http://search.yahoo.com

Igor Kleshchevich

unread,
Apr 29, 2003, 1:56:57 PM4/29/03
to Paul, Larry Wall, perl6-l...@perl.org, Hod...@writeme.com

P> You know, even though it lacks the humor factor, that really is also
P> kind of a cool idea. I think it would ger\nerally increase my
P> likelihood to use a language if it actually had a please() operator,

Well, you can try INTERCAL. It has C<PLEASE> keyword, as in
PLEASE WRITE IN :1
:-)


Igor

0 new messages