Front page | perl.perl5.porters |
Postings from July 2020
Re: Types in Cor (and Perl)
From: Darren Duncan
July 13, 2020 08:58
Re: Types in Cor (and Perl)
Message ID: email@example.com
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:
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
> 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