Mailing List Archive

Types in Cor (and Perl)
Hi all (directly copying Dave as this could impact his signature work),

This might seem premature give that Perl 7 is still being actively discussed, but I'm hitting a stumbling block in Cor's design regarding types. (I assume types cannot be implemented in the first release unless we steal from Types::Standard and friends). For quite some time, I've had things like this in my examples:

has $foo :isa(Int);

However, I know that Dave Mitchell is working on signatures and he's looking at types too. If we have types in signatures and types in Cor, we're eventually going to get to the point of someone expecting this to work:

my $foo :isa(Int);

In other words, Perl will support gradual typing with all of the lovely safety that so many of us crave (or maybe just I do?)

However, we have both syntax and semantic issues. Dave's proposal (https://www.nntp.perl.org/group/perl.perl5.porters/2019/11/msg256683.html) looks very clear and, given that it predates Cor, it's not surprising that his syntax is different from Cor's syntax. If Perl is going to have types, we do not want different syntax for signatures, variable declarations, and class slot declarations.
The reason Cor uses attributes is because the has declarator, unlike in Moo/se, only declares the instance variable. It does nothing else. All other behaviors are provided via attributes and those attributes are almost fully composable (I've tried hard to decouple everything). For example, a 2D Point class that allows you to read and write the x/y data looks like this:

class Point {
    has ( $x, $y ) :reader :writer :new :isa(Num);

    method invert () {
        return Point->new( x => $y, y => $x );
    }
}

Attributes are very familiar to Perl developers and it seemed an easy  way to extend things. Going with Dave's proposal, I'd have to do this:

has ( $x, $y ) :reader :writer :new is Num;

I find that a touch jarring, but I could live with it. Whatever syntax we go with, it needs to be nailed down so design work can continue.
That brings me to semantics.

I've been doing a moderate amount of reading about type systems and one thing that stands out is that bolting type systems onto languages without "traditional" type systems is hard. While I've opened a ticket about this, I think it would be particularly helpful if people were to read a follow-up comment about what types would mean in Perl. The summary: Perl's behavior, absent types, should not change. Perl's behavior, with types, should provide a sound type system and not try to emulate Perl's behavior. (you can throw rotten tomatoes at me now).
I know very little of Perl's internals or what this would mean. For Cor V1, I'd be tempted to go with attributes and Types::Standard (:isa(ArrayRef[Int])), but I strongly suspect that it will conflict with David's work, and it won't provide the type safety one would expect.
If there are strong counter-arguments, I'd be delighted to say I was wrong.

Best,Ovid
-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl
Re: Types in Cor (and Perl) [ In reply to ]
On Sun, Jul 12, 2020 at 8:05 AM Ovid via perl5-porters <
perl5-porters@perl.org> wrote:

> I know very little of Perl's internals or what this would mean. For Cor
> V1, I'd be tempted to go with attributes and Types::Standard (
> :isa(ArrayRef[Int])), but I strongly suspect that it will conflict with
> David's work, and it won't provide the type safety one would expect.
>

Rather than just borging Types::Standard directly I think it's worth
thinking more about what a type system might look like. One huge issue I
have with Types::Standard is that it just copies the mistakes of Moose, so
let's not copy them into the core!

Specifically, I think having a `Str` type that doesn't accept objects which
overload (and similar for other types) is a huge mistake. Of course, once
you start thinking about this you start going down the rabbit hole of
stringification and what it means for something to stringify, since _every_
type in Perl can stringify, but maybe not usefully. Then you start thinking
about things like roles and have a `Stringies` role or something like that.

Is that a road worth going down? I really can't say. But at the very least
it's worth thinking about, and if the core were to explicitly reject that,
it's worth documenting.


Cheers,

Dave Rolsky
http://blog.urth.org
https://github.com/autarch
Re: Types in Cor (and Perl) [ In reply to ]
On Mon, 13 Jul 2020 at 03:52, Dave Rolsky <autarch@urth.org> wrote:

> On Sun, Jul 12, 2020 at 8:05 AM Ovid via perl5-porters <
> perl5-porters@perl.org> wrote:
>
>> I know very little of Perl's internals or what this would mean. For Cor
>> V1, I'd be tempted to go with attributes and Types::Standard (
>> :isa(ArrayRef[Int])), but I strongly suspect that it will conflict with
>> David's work, and it won't provide the type safety one would expect.
>>
>
> Rather than just borging Types::Standard directly I think it's worth
> thinking more about what a type system might look like. One huge issue I
> have with Types::Standard is that it just copies the mistakes of Moose, so
> let's not copy them into the core!
>
>
Great point, question IMHO is do we mean/need/want types or constraints?

Difference:
- constraint is evaluated runtime
- type is declared and trusted

Child type can via inheritance break a constraint imposed by parent type.

Examples with primitive types look nice, but ... who uses primitives and
strong types ?
Re: Types in Cor (and Perl) [ In reply to ]
On 2020-07-12 7:07 p.m., Branislav Zahradník wrote:
> Great point, question IMHO is do we mean/need/want types or constraints?

Yes we definitely do.

> Difference:
> - constraint is evaluated runtime
> - type is declared and trusted

Not necessarily.

I see types and constraints are fundamentally one and the same thing.

A type is fundamentally just a set of values, such as the set of integer values
or the set of array values or the set of all values.

The most generic form of a type definition is a predicate (boolean-resulting)
monadic function that takes any value as input and results in true or false if
the value is a member of the type (set of values) or not.

Whether or not anything is evaluated at runtime or not is entirely dependent on
whether an input to that evaluation comes from the user or the environment,
whereas if everything we need to know is available at compile time it CAN be
evaluated at compile time. The simplest implementations would evaluate at
runtime but the more optimized the system is the more it moves to compile time.
This is related to the concept of folding.

> Child type can via inheritance break a constraint imposed by parent type.

That depends on how the child and parent types are defined. If the child is
defines as a subset of the parent, then it can't.

> Examples with primitive types look nice, but ... who uses primitives and strong
> types ?

Primitives and strong types are very frequently used.

The whole concept of primitive types is mostly arbitrary. For example, is a
character string a primitive type or is it an array of characters?

Strong types are not tied to primitive types, they are very separate concepts.

Generally strong typing means that if you declare something expects an actual
string, it will only accept a string and not just something that can stringify;
strong typing would require you to explicitly cast the other thing to the
string. Whereas weak typing would just let you use the thing that isn't a
string in contexts that specifically ask for a string.

Don't confuse generic types with weak typing; the former is explicitly saying a
wider range of values is accepted; the latter is more about ignoring declared
intentions and pounding square pegs into round holes.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
> A type is fundamentally just a set of values, such as the set of integer values
> or the set of array values or the set of all values.
A tiny clarification. A type is a named set of values along with with the operations allowed on it. For example, both a Dollar and Euro type might contain the same set of values, with the same operations on them, but you can't add a Dollar and Euro together because semantically, that doesn't make sense. You also couldn't ask if one is greater than the other because, again, that doesn't make sense (this is one thing which annoys me about databases: they "protect" your data and offer almost no type safety).
Thus, something that would be awesome for a type system is not only allowing subsets, but type cloning (made up syntax):

define Dollar as Num;define Euro   as Num;
my $dollars :isa(Dollar) = 100;my $euros   :isa(Euro)   = 200;
my $avg = ( $dollars + $euros )/2; # run-time exception

Powerful, on-the-fly safety to prevent a common error. They may derive from Num values, but because the type names are different, we do not automatically have operations defined between them.

As for objects, a class is merely a user-defined type. The set of values it can contain is complex and the methods are the allowed operations. I suspect that if our type system makes a huge, user-visible, distinction between these and built-in types, we might want to consider if a mistake is made. (I'm unsure on this case)

Best,Ovid
--
IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Monday, 13 July 2020, 07:02:39 CEST, Darren Duncan <darren@darrenduncan.net> wrote:

On 2020-07-12 7:07 p.m., Branislav Zahradník wrote:
> Great point, question IMHO is do we mean/need/want types or constraints?

Yes we definitely do.

> Difference:
> - constraint is evaluated runtime
> - type is declared and trusted

Not necessarily.

I see types and constraints are fundamentally one and the same thing.



The most generic form of a type definition is a predicate (boolean-resulting)
monadic function that takes any value as input and results in true or false if
the value is a member of the type (set of values) or not.

Whether or not anything is evaluated at runtime or not is entirely dependent on
whether an input to that evaluation comes from the user or the environment,
whereas if everything we need to know is available at compile time it CAN be
evaluated at compile time.  The simplest implementations would evaluate at
runtime but the more optimized the system is the more it moves to compile time.
This is related to the concept of folding.

> Child type can via inheritance break a constraint imposed by parent type.

That depends on how the child and parent types are defined.  If the child is
defines as a subset of the parent, then it can't.

> Examples with primitive types look nice, but ... who uses primitives and strong
> types ?

Primitives and strong types are very frequently used.

The whole concept of primitive types is mostly arbitrary.  For example, is a
character string a primitive type or is it an array of characters?

Strong types are not tied to primitive types, they are very separate concepts.

Generally strong typing means that if you declare something expects an actual
string, it will only accept a string and not just something that can stringify;
strong typing would require you to explicitly cast the other thing to the
string.  Whereas weak typing would just let you use the thing that isn't a
string in contexts that specifically ask for a string.

Don't confuse generic types with weak typing; the former is explicitly saying a
wider range of values is accepted; the latter is more about ignoring declared
intentions and pounding square pegs into round holes.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
Hi Ovid,
I think you might confuse value type and refence type. General speaking, a type of CS is divided by 2 set:

one is value type, this is more or less pure data stored on memory, like int, uint, struct,(maybe including char)
another is reference type, it does some abstraction and package on the real data for human , like class type, string etc.

I think if Perl would add a type system, it'd better think about both above type.



________________________________
From: Ovid via perl5-porters <perl5-porters@perl.org>
Sent: Monday, July 13, 2020 3:28 PM
To: Branislav Zahradn?k <happy.barney@gmail.com>; Perl5 Porters <perl5-porters@perl.org>; Darren Duncan <darren@darrenduncan.net>
Subject: Re: Types in Cor (and Perl)

> A type is fundamentally just a set of values, such as the set of integer values
> or the set of array values or the set of all values.

A tiny clarification. A type is a named set of values along with with the operations allowed on it. For example, both a Dollar and Euro type might contain the same set of values, with the same operations on them, but you can't add a Dollar and Euro together because semantically, that doesn't make sense. You also couldn't ask if one is greater than the other because, again, that doesn't make sense (this is one thing which annoys me about databases: they "protect" your data and offer almost no type safety).

Thus, something that would be awesome for a type system is not only allowing subsets, but type cloning (made up syntax):

define Dollar as Num;
define Euro as Num;

my $dollars :isa(Dollar) = 100;
my $euros :isa(Euro) = 200;

my $avg = ( $dollars + $euros )/2; # run-time exception

Powerful, on-the-fly safety to prevent a common error. They may derive from Num values, but because the type names are different, we do not automatically have operations defined between them.

As for objects, a class is merely a user-defined type. The set of values it can contain is complex and the methods are the allowed operations. I suspect that if our type system makes a huge, user-visible, distinction between these and built-in types, we might want to consider if a mistake is made. (I'm unsure on this case)

Best,
Ovid
--
IT consulting, training, specializing in Perl, databases, and agile development
http://www.allaroundtheworld.fr/.

Buy my book! - http://bit.ly/beginning_perl


On Monday, 13 July 2020, 07:02:39 CEST, Darren Duncan <darren@darrenduncan.net> wrote:


On 2020-07-12 7:07 p.m., Branislav Zahradn?k wrote:
> Great point, question IMHO is do we mean/need/want types or constraints?

Yes we definitely do.

> Difference:
> - constraint is evaluated runtime
> - type is declared and trusted

Not necessarily.

I see types and constraints are fundamentally one and the same thing.



The most generic form of a type definition is a predicate (boolean-resulting)
monadic function that takes any value as input and results in true or false if
the value is a member of the type (set of values) or not.

Whether or not anything is evaluated at runtime or not is entirely dependent on
whether an input to that evaluation comes from the user or the environment,
whereas if everything we need to know is available at compile time it CAN be
evaluated at compile time. The simplest implementations would evaluate at
runtime but the more optimized the system is the more it moves to compile time.
This is related to the concept of folding.

> Child type can via inheritance break a constraint imposed by parent type.

That depends on how the child and parent types are defined. If the child is
defines as a subset of the parent, then it can't.


> Examples with primitive types look nice, but ... who uses primitives and strong
> types ?


Primitives and strong types are very frequently used.

The whole concept of primitive types is mostly arbitrary. For example, is a
character string a primitive type or is it an array of characters?

Strong types are not tied to primitive types, they are very separate concepts.

Generally strong typing means that if you declare something expects an actual
string, it will only accept a string and not just something that can stringify;
strong typing would require you to explicitly cast the other thing to the
string. Whereas weak typing would just let you use the thing that isn't a
string in contexts that specifically ask for a string.

Don't confuse generic types with weak typing; the former is explicitly saying a
wider range of values is accepted; the latter is more about ignoring declared
intentions and pounding square pegs into round holes.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
On Sun, Jul 12, 2020 at 3:05 PM Ovid via perl5-porters
<perl5-porters@perl.org> wrote:
>
> Hi all (directly copying Dave as this could impact his signature work),
>
> This might seem premature give that Perl 7 is still being actively discussed, but I'm hitting a stumbling block in Cor's design regarding types. (I assume types cannot be implemented in the first release unless we steal from Types::Standard and friends). For quite some time, I've had things like this in my examples:
>
> has $foo :isa(Int);
>
>
> However, I know that Dave Mitchell is working on signatures and he's looking at types too. If we have types in signatures and types in Cor, we're eventually going to get to the point of someone expecting this to work:
>
> my $foo :isa(Int);
>
>
> In other words, Perl will support gradual typing with all of the lovely safety that so many of us crave (or maybe just I do?)
>
> However, we have both syntax and semantic issues. Dave's proposal (https://www.nntp.perl.org/group/perl.perl5.porters/2019/11/msg256683.html) looks very clear and, given that it predates Cor, it's not surprising that his syntax is different from Cor's syntax. If Perl is going to have types, we do not want different syntax for signatures, variable declarations, and class slot declarations.
>
> The reason Cor uses attributes is because the has declarator, unlike in Moo/se, only declares the instance variable. It does nothing else. All other behaviors are provided via attributes and those attributes are almost fully composable (I've tried hard to decouple everything). For example, a 2D Point class that allows you to read and write the x/y data looks like this:
>
> class Point {
> has ( $x, $y ) :reader :writer :new :isa(Num);
>
> method invert () {
> return Point->new( x => $y, y => $x );
> }
> }
>
>
> Attributes are very familiar to Perl developers and it seemed an easy way to extend things. Going with Dave's proposal, I'd have to do this:
>
> has ( $x, $y ) :reader :writer :new is Num;
>
>
> I find that a touch jarring, but I could live with it. Whatever syntax we go with, it needs to be nailed down so design work can continue.
>
> That brings me to semantics.
>
> I've been doing a moderate amount of reading about type systems and one thing that stands out is that bolting type systems onto languages without "traditional" type systems is hard. While I've opened a ticket about this, I think it would be particularly helpful if people were to read a follow-up comment about what types would mean in Perl. The summary: Perl's behavior, absent types, should not change. Perl's behavior, with types, should provide a sound type system and not try to emulate Perl's behavior. (you can throw rotten tomatoes at me now).
>
> I know very little of Perl's internals or what this would mean. For Cor V1, I'd be tempted to go with attributes and Types::Standard (:isa(ArrayRef[Int])), but I strongly suspect that it will conflict with David's work, and it won't provide the type safety one would expect.
>
> If there are strong counter-arguments, I'd be delighted to say I was wrong.
>
> Best,
> Ovid

There are (at least) three kinds of type system like things that you
could want. And before we continue this discussion it is probably
important to specify exactly what we're trying to achieve here.

1. Input/output validation.

This is achievable right now without major modification to the
implementation as it is "just" syntax smithing around things that are
already possible. Essentially this is what Dave proposed.

2. Typed values.

As far as I know there are four kinds of scalar values visible in user
code (but I'm half expecting someone to point out we have another
obscure one that I forgot):
a. References. We all know these. These can be divided further into
blessed into various packages.
b. Undefined. This speaks for itself.
c. Regexp. This is actually always hidden behind a reference (I think
since 5.12), so you probably should also pretend these don't exist. I
don't really think we are guaranteeing they will keep existing in this
way in the future anyway.
d. Fakeglobs. These are fairly esoteric and generally considered a bad
thing. If you don't know what I'm talking about, you may want to keep
it that way.
e. Primitives (stringy, numeric, wibbly wobbly).

So essentially, the scalar type system is "reference, undef or other".
Further typing of references is mostly obvious and undefs don't have
further typing, but primitives are not so simple. As far as the
implementation is concerned we don't have a concept of "the type of
this is integer". Any integer concept would be subsetting, e.g. "It's
an other, that looks like a number". Changing that at this stage would
be difficult as both pure-perl code and xs have been making
assumptions about that for 30 years.

Typed primitive types are a quagmire, but without primitives it seems
of limited use.

3. Typed variables.

We don't have much of a concept of a variable as separate from a value
(the way Raku has with its containers), not in the last place because
values are mutable unless they're not. This does make it quite a bit
harder to have anything like typed variables. All the solutions I can
think up for that are terrible and break really quickly.

Quite frankly anything other than option 1 seems like a massive undertaking.

Leon





Leon
Re: Types in Cor (and Perl) [ In reply to ]
On 2020-07-13 12:28 a.m., Ovid wrote:
> > A type is fundamentally just a set of values, such as the set of integer values
> > or the set of array values or the set of all values.
>
> A tiny clarification. A type is a named set of values along with with the
> operations allowed on it. For example, both a Dollar and Euro type might contain
> the same set of values, with the same operations on them, but you can't add a
> Dollar and Euro together because semantically, that doesn't make sense. You also
> couldn't ask if one is greater than the other because, again, that doesn't make
> sense (this is one thing which annoys me about databases: they "protect" your
> data and offer almost no type safety).

Ovid, your example above seems to be confusing the issue, or you have
misunderstood what I meant to say.

When I say "value" I mean an individual constant that is not fixed in time or
space; every "value" is unique, eternal, and immutable; it has no address and
can not be updated. Two value appearances X and Y are the same value, in the
sense of a generic identity/equality comparison, if and only if, there does not
exist any test or operation that gives a different result or behaves differently
when given Y as input in place of X.

Therefore, if we expect that there are any operations for which it is not valid
for a Euro or Dollar to be substituted for each other, then there does not exist
any value that is both a Euro and a Dollar, and the Euro and Dollar types do NOT
have any values in common.

Similarly, generic numbers are also distinct values from Euro and Dollar, all 3
are mutually disjoint and have no values in common. An Euro and a Dollar may be
characterized by a number, but they are not the same value as a number.

In that sense, your statement above that a Dollar and Euro type may have values
in common contradicts your statement that Dollar and Euro values can not be
added or ordered with each other.

I say again that a type is just a set of values, and the identity of a type is
the set of values comprising it. Operations are not part of a type, rather they
are separate things you can do with values of a type. It is part of the
definition of an operator as to what values may be taken as inputs.

The thing about DBMSs, its not so much that they don't have type safety, its
more that in the typical case they only have a small set of system-defined types
and they don't allow users to define their own types.

If DBMSs allowed user-defined types such as Euro and Dollar then the DBMS can
also be type-safe in a more useful way.

But because they don't allow this, users have to map their Euro/Dollar values to
generic number values or such in order to store them.

(Note that we agree that DBMSs being very lacking here, and I'm actually working
on a solution to this, a DBMS that DOES support user-defined types and hence
full type safety. But that's off topic for the current discussion.)

> Thus, something that would be /awesome/ for a type system is not only allowing
> subsets, but type /cloning/ (made up syntax):
>
> define Dollar as Num;
> define Euro   as Num;
>
> my $dollars :isa(Dollar) = 100;
> my $euros   :isa(Euro)   = 200;
>
> my $avg = ( $dollars + $euros )/2; # run-time exception

The type cloning you mention is definitely useful, but its important to
recognize that its just a convenient syntax for making a new disjoint type that
is characterized by or isomorphic to an existing one.

Implementation-wise, Dollar and Euro here would likely be classes whose objects
have 1 attribute each that is Num-typed.

To borrow some Raku Pair syntax, each of these is a literal for a distinct value:

:Num<42>
:Euro<42>
:Dollar<42>

Some of your code above then if strongly typed would be like this:

my $dollars :isa(Dollar) = :Dollar<100>;
my $euros :isa(Euro) = :Euro<200>;

The strong typing belongs fundamentally to the value, but it can also belong to
the variables. One could just as easily say for the last statement:

my $avg = (:Dollar<100> + :Euro<200>)/2; # run-time exception

But also this is "at least" a run-time exception, and it might also be caught at
compile time instead if the compiler is smart enough or has enough information.

> Powerful, on-the-fly safety to prevent a common error. They may derive from Num
> values, but because the type names are different, we do not automatically have
> operations defined between them.

I think in the sense you're saying, its not just about names. If we have a type
known by the name Foo and then we declare Bar as an alias for Foo, then those
are 2 names referring to the same type. Whereas, if the values themselves are
represented by a <label,payload> (example <Str,Num>) pair such that the
label/str was eg "Euro", then <Euro,42> is distinct from <Dollar,42>. Operators
are separately defined to expect <Euro,*> or <Dollar,*> and hence you get the
type safety.

> As for objects, a /class/ is merely a user-defined /type/. The set of values it
> can contain is complex and the methods are the allowed operations. I suspect
> that if our type system makes a huge, user-visible, distinction between these
> and built-in types, we might want to consider if a mistake is made. (I'm unsure
> on this case)

Yes, in an object-oriented language, a type is represented by a class and a
value is represented by an object. The "clone" you mention is just shorthand
syntax for defining a class.

What we typically want is for there to be no arbitrary distinction between
system-defined types and user-defined types. They should all be subject to the
same rules and syntax. In this sense the system-defined types are just
pre-defined classes that automatically are available and users can't change them.

Example, in Java/C#/etc the types/classes Object and such are system-defined but
usable the same ways as user-defined ones.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
On 2020-07-13 1:43 a.m., Andy Xiao wrote:
> Hi Ovid,
>  I think you might confuse value type and refence type. General speaking, a
> type of CS is divided by 2 set:
>
> one is value type,  this is more or less pure data stored on memory, like int,
> uint, struct,(maybe including char)
> another is reference type,  it does some abstraction and package on the real
> data for human , like class type, string etc.
>
> I think if Perl would add a type system, it'd better think about both above type.

Andy, yes you are right.

(Please see my previous reply to Ovid for context, which this is an addendum to.)

How I would characterize the distinction is that all types are value types, and
all values are immutable, but that some values are handles/references for
typically-anonymous variables.

The actual immutable value is effectively the memory address of the variable,
but the format of the memory address is by default a black box to the user. In
a debugging situation the address typically is represented by an integer, but
that's implementation-dependent.

So, following my definition of what value equality is, no way of telling X and Y
apart, it stands to reason that 2 handle/reference value appearances X and Y are
the same value if and only if they point to the same variable.

In a language where everything is an object, an object being mutable is the same
as that object being a handle/reference value, whereas an object that isn't
mutable is not a handle/reference.

In typical parlance, generic equality tests do a shallow/reference comparison
for mutable objects and they do a deep comparison for immutable ones.

Or to be more specific, if an immutable object has attributes of mutable types,
then comparison if the immutable object is only as deep as the mutable attributes.

A key advantage of defining general equality as I have is that it is guaranteed
to be fully deterministic. When you don't cross reference boundaries into
variables, you are guaranteed that any operation you do will produce the same
result every time, and so you can use that for indexing or other things with
your conclusions never becoming invalid.

I will point out that the generic equality test I mention is something that must
be built-in to the language and it must work for all types including
user-defined types, and users must not be able to override it. This is as basic
as the generic assignment operator, which users don't override either.

If users want to conceptually override the definition of equality, say to
support case-insensitive compares, they should have to name that something else.
See also Raku having distinct =:= and === and == and eq operators.

Note that comparing different types for generic equality is completely valid and
well-understood and logical; the operator simply returns false when given say a
number and a string. The signature of the operator is (Any,Any).

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
I see types and constraints are fundamentally one and the same thing.
>
> A type is fundamentally just a set of values, such as the set of integer
> values
> or the set of array values or the set of all values.
>
>
example (I found such code in java codebase):
class Limit { ... enforces min/max 0/1000 }

class Foo extends Limit { Foo (int i) { super (i/3) } }

Type check: Foo is a Limit
Constraint check: Foo is not a Limit (only 1/3)



>
> Primitives and strong types are very frequently used.
>
> The whole concept of primitive types is mostly arbitrary. For example, is
> a
> character string a primitive type or is it an array of characters?
>
>
Strong types are not tied to primitive types, they are very separate
> concepts.
>
>
Fair point. So let me define what I understand as a primitive type:
- primitive type defines a storage class of data (I/O serialization)
- non-primitive type defines meaning of data.

Under strong types concept I do understand the strong definition of meaning
of data.

So commenting Ovid's Dollar/Euro example:
- Num is primitive type
- Dollar/Euro are non-primitive types
Re: Types in Cor (and Perl) [ In reply to ]
First, thanks to those who've taken the time to correct some of my misunderstandings.
Second:
> So commenting Ovid's Dollar/Euro example:> - Num is primitive type
> - Dollar/Euro are non-primitive types
If we make a distinction, I think the terminology could be improved to help clarify the meaning. Maybe "built-in" versus "derived"? If we can pick terminology which is self-defining, I think fewer misconceptions might occur.

Best,
Ovid
-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Monday, 13 July 2020, 16:30:03 CEST, Branislav Zahradník <happy.barney@gmail.com> wrote:




I see types and constraints are fundamentally one and the same thing.

A type is fundamentally just a set of values, such as the set of integer values
or the set of array values or the set of all values.



example (I found such code in java codebase):class Limit { ... enforces min/max 0/1000 }

class Foo extends Limit { Foo (int i) { super (i/3) } }

Type check: Foo is a LimitConstraint check: Foo is not a Limit (only 1/3)

 


Primitives and strong types are very frequently used.

The whole concept of primitive types is mostly arbitrary.  For example, is a
character string a primitive type or is it an array of characters?
 


Strong types are not tied to primitive types, they are very separate concepts.



Fair point. So let me define what I understand as a primitive type:- primitive type defines a storage class of data (I/O serialization)- non-primitive type defines meaning of data.

Under strong types concept I do understand the strong definition of meaning of data.
So commenting Ovid's Dollar/Euro example:- Num is primitive type
- Dollar/Euro are non-primitive types
Re: Types in Cor (and Perl) [ In reply to ]
Hi Ovid,

First, thanks for giving this what is evidently a lot of thought.

I'm currently busy trying to keep things moving on several fronts
(`LEAVE`, `try/catch`, firstclass exceptions, dumbmatch aka "a better
switch", as well as the ongoing Perl 7 thoughts), but I thought I'd
write a brief holding note.

I agree that signatures, variables, object slots, etc.. all want to use
a single unified idea. What that idea is yet, I don't know. But they
need it. I intend to come back and give it a good amount of thought and
experimentation at some point soon because it will overlap with several
things later down my queue. I'll be sure to come back and see what
research and ideas you have conducted when I do.

The way I see it, there's three different reasons to want "types". I'm
not saying that any reason is more valid than the others, but there are
three distinct (and maybe-overlapping) reasons, and any further
discussion on what a "type system" is needs first to consider why you
want that in the first place:

1) I want my compiler to tell me I have written a program that can
never work (aka. the static typing on variables/functions/etc..)

2) I want my runtime to tell me I am operating on the wrong data (aka
the runtime arguments/return type assertions)

3) I want my runtime to perform faster because I have restricted what
operations it might be expected to do (e.g. consider `use integer`).

Different people who ask for "types" are often asking for different
ones. It helps to be clear what type of type people are after because
only then can you begin to design a system that would cover their
use-case.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Types in Cor (and Perl) [ In reply to ]
On 2020-07-13 8:18 a.m., Ovid via perl5-porters wrote:
> If we make a distinction, I think the terminology could be improved to help
> clarify the meaning. Maybe "built-in" versus "derived"? If we can pick
> terminology which is self-defining, I think fewer misconceptions might occur.

I agree that this is much better.

The primary distinction I see for type categories is "system-defined"/"built-in"
and "user-defined". The first category assumes the user can not change it.

Generally speaking, whenever a type is defined by the system, language
implementations have free reign to implement them how they want behind the
scenes as long as the user-exposed behavior doesn't change, and there is a lot
of latitude for special-case optimization.

Being system-defined does not have any relation in general to whether a type
maps to something the hardware specifically knows about such as a "signed 32-bit
integer".

But in practice it is best for a language to anticipate the hardware and provide
some canonical way to have data types somehow that directly map to those so that
the compiler/runtime doesn't have to be as clever to know when it can use them.

On a tangent, I feel that it is a hallmark of a modern language if a "big
integer" / unlimited-size integer type is a standard built-in, or better yet is
THE type used by idiomatic code. Raku Int is an example of this. In the Perl 5
case this basically means Math::BigInt or such receiving special treatment and
receiving syntax that it can be used as tersely as traditional scalars. Behind
the scenes, machine integers can still be used when the integers fit in them but
promotion is more automatic, and no more overflows/etc.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
Is there any reason not to use the existing syntax for types?
my Foo::Bar $x;

"Existing" because Perl already understands this (any perl5, I think;
certainly as far back as 5.8). It doesn't *do* anything, but perl can
parse it (and will warn if there is no Foo::Bar package).

You can even make it do something with Vincent Pit's Lexical::Types.
https://metacpan.org/pod/Lexical::Types
Re: Types in Cor (and Perl) [ In reply to ]
David asked:
> Is there any reason not to use the existing syntax for types?
>  my Foo::Bar $x;
I deliberately avoided that because of this from perldoc -f my:

       my TYPE VARLIST : ATTRS

The exact semantics and interface of TYPE and ATTRS are still evolving.  TYPE may be a bareword, a constant declared with "use constant", or "__PACKAGE__".  It is currently bound to the use of the fields pragma, and attributes are handled using the attributes pragma, or starting from Perl 5.8.0 also via the Attribute::Handlers module.  See "Private Variables via my()" in perlsub for details.
So there's already some behavior attached to it and I was concerned about hijacking that behavior for something else and possibly breaking existing code.
Best,Ovid
-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Tuesday, 14 July 2020, 03:35:14 CEST, David Green <david.green@pl-comme.ci-comme.ca> wrote:

Is there any reason not to use the existing syntax for types?
  my Foo::Bar $x;

"Existing" because Perl already understands this (any perl5, I think;
certainly as far back as 5.8).  It doesn't *do* anything, but perl can
parse it (and will warn if there is no Foo::Bar package).

You can even make it do something with Vincent Pit's Lexical::Types.
  https://metacpan.org/pod/Lexical::Types
Re: Types in Cor (and Perl) [ In reply to ]
On Tue, 14 Jul 2020 at 09:29, Ovid via perl5-porters <perl5-porters@perl.org>
wrote:

> David asked:
>
> > Is there any reason not to use the existing syntax for types?
> > my Foo::Bar $x;
>
> I deliberately avoided that because of this from perldoc -f my:
>
>
probably unrelated to Cor itself, but I just have a feeling that it will
benefit from firstclass class literal (like raku's :U or java's .class, but
more perlish)

Both usage and syntax may be easier (just gut feeling)

Brano
Re: Types in Cor (and Perl) [ In reply to ]
On Tue, 14 Jul 2020 07:29:28 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> The exact semantics and interface of TYPE and ATTRS are still
> evolving.  TYPE may be a bareword, a constant declared with "use
> constant", or "__PACKAGE__".

> So
> there's already some behavior attached to it and I was concerned
> about hijacking that behavior for something else and possibly
> breaking existing code.

Some other core folks might correct me here, but it is my vague
recollection that, besides needing to be a valid package name, there
isn't actually any behaviour currently assigned by core perl to that
information.

So while you can

package A::Typename;

my A::Typename $var;

in practice nothing changes if you do that.


That said I would still caution against using this syntax for that
purpose, precisely because it only allows package names whereas we are
likely to want to specify type names - such type names could be
"behaves like an integer"

$ perl -e 'my aninttype $var'
No such class aninttype at -e line 1, near "my aninttype"

Finally, I would prefer not to have to complicate grammars in lots of
other places (`has` slots, sub signatures) by simply juxtaposing an
optional typename into the syntax. Far nicer are the ideas that
involve a definite "introduction" keyword, such as an `:is` attribute.

Given a choice between

my inttype $x;

my $x :is(int); # or some other keyword name/syntax to be bikeshedded

I would definitely prefer the second.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Types in Cor (and Perl) [ In reply to ]
Just saw this (took a break from reading p5p email, ended up being a month) and answering below.

On Sun, Jul 12, 2020, at 19:52, Dave Rolsky wrote:
> Specifically, I think having a `Str` type that doesn't accept objects
> which overload (and similar for other types) is a huge mistake. Of
> course, once you start thinking about this you start going down the
> rabbit hole of stringification and what it means for something to
> stringify, since _every_ type in Perl can stringify, but maybe not
> usefully. Then you start thinking about things like roles and have a
> `Stringies` role or something like that.

Which is why I (personally) would want to have a Str type that accepts objects that overload AND a StrictStr type that does not. The ability to allow or reject that as desired would be nice to have.
Re: Types in Cor (and Perl) [ In reply to ]
On 2020-07-31 3:31 p.m., Curtis Jewell wrote:
> On Sun, Jul 12, 2020, at 19:52, Dave Rolsky wrote:
>> Specifically, I think having a `Str` type that doesn't accept objects
>> which overload (and similar for other types) is a huge mistake. Of
>> course, once you start thinking about this you start going down the
>> rabbit hole of stringification and what it means for something to
>> stringify, since _every_ type in Perl can stringify, but maybe not
>> usefully. Then you start thinking about things like roles and have a
>> `Stringies` role or something like that.
>
> Which is why I (personally) would want to have a Str type that accepts objects that overload AND a StrictStr type that does not. The ability to allow or reject that as desired would be nice to have.

Really we should just be stealing useful stuff from Raku here.

What we want is 2 distinct categories based on classes and roles.

If someone wants "any object that can stringify" then they choose the Stringy
role as their type.

If someone wants strictly the built in string type, then they choose the Str class.

Its as simple as that.

And I personally would want to use the strict type by default most of the time.

-- Darren Duncan
Re: Types in Cor (and Perl) [ In reply to ]
On Fri, Jul 31, 2020 at 6:52 PM Darren Duncan <darren@darrenduncan.net> wrote:

> Really we should just be stealing useful stuff from Raku here.
>
> What we want is 2 distinct categories based on classes and roles.
>
> If someone wants "any object that can stringify" then they choose the Stringy
> role as their type.
>
> If someone wants strictly the built in string type, then they choose the Str class.
>
> Its as simple as that.
>
> And I personally would want to use the strict type by default most of the time.
>
> -- Darren Duncan

Glad this is the bottom of the thread, because it's a perfect
introduction to Raku's type system which
is a very intense thing and worth leafing through just to see what
some other thoughtful committee
decided.


https://docs.raku.org/type/Any#Type_Graph


--
"You can be in my dream if I can be in yours." -- Bob Dylan