This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Kawa type-conversions


[Some thoughts about Kawa type-checking and type-conversions.
I don't know when any of this will be implemented, but this is
what I'm currently thinking makes most sense - though some details
would be need to be worked out in practice.  Maybe we can think
of this as a sketch for a Kawa Enhancement Proposal.]

Right now Kawa has multiple syntaxes for type conversion:

(as TYPE VALUE)

(->TYPE VALUE)

(define VAR ::TYPE VALUE) ;; and other variants using type specifiers

These mostly allow the same set of conversions, but using 'as' is more
"lenient" than '->TYPE' in that it allows also conversions of the the
raw types are the same.  (This is made use of in converting between the
tring-cursor type and int, for example.)

We also have type tests:

(? VAR ::TYPE VALUE) ;; generalizable to patterns: (? PATTERN VALUE)

(instance? VALUE TYPE)

These aren't really consistent:

(if (? x::int 3.4) x #f) ==> 3
(instance? 3.4 int) ==> 3

At some point I'd like to experiment with a --strict-typing option,
so it's desirable to come up consistent and useful model.

So what I'm thinking we shoudl aim for:

* (as TYPE VALUE) would be short-hand for
  (let ((TMP ::TYPE VALUE)) TMP)
and so the set of allowable conversions would be the same.

* Using 'as' or a type-specifier would invoke an *implicit*
conversion.  Using (->TYPE VALUE) would be an *explicit* conversion,
and would allow more conversions.

* As a general rule implicit conversion of VALUE to TYPE should be
OK if (instance? VALUE TYPE) or if it's a loss-less conversion to
semantically more-or-less the same type.  We may need to fine-tune this.

* As a general rule (? VAR::TYPE VALUE) should succeed if
(as TYPE VALUE) doesn't throw an exception. We may need to fine-tune this.

* It seems reasonable to introduce:
  (convert TYPE VALUE)
as equivalent to:
  (->TYPE VALUE)

* As an example (->list SEQUENCE) would convert any SEQUENCE value
to a list.  It would be equivalent to (list @SEQUENCE) except it
wouldn't necessarily make a fresh copy if the SEQUENCE is a list.

  (->list #(3 4 5)) ==> (3 4 5)
  (as list #(3 4 5)) ==> ERROR
  (define x::list #(3 4 5)) ==> ERROR

* Assume we a new type sequence, optionally parameterized as
sequence[ELEMENT-TYPE].  This would match any type allowed
for splicing or the new generalized map, including strings
and native Java arrays.  Since all of these types are "instances"
of the sequence types, all of these types can be *implicitly*
converted to sequence - even if we have to allocate a wrapper
object.

In general, special types that aren't just native Java types
might require custom conversion methods - and may need different
methods for implicit and explicit conversions.

* As an incompatible change, converting float to int should (IMO) no
longer be allowed for implicit conversions:

  (->int 3.4) ==> 3
  (as int 3.4) ==> ERROR ;; incompatible change
  (define x::int 3.4) ==> ERROR ;; incompatible change

* In general static type-checking wouldn't change much from today,
except for some corner cases.  For example assigning a double to an int
using be dis-allowed if using an implicit conversion but allowed if
using an explicit conversion.

* If we implement strict type-checking, it would be only be enabled
by a flag like --strict-typing.  In that case implicit conversions
change so that the *type* of the VALUE expression needs to be a sub-type
of the required TYPE.  For example example you can't convert an
expression of type java.util.List to a required type java.util.ArrayList.
This would be ok with non-strict type-checking as long as the expression
type and the required type have a non-empty intersection.

Explicit conversion should work the same with strict and non-strict type-checking:
It would be allowed as long as the types have a non-empty intersection.

* If we implement strict type-checking, we'd also define a new 'dynamic' type,
similar to C#.  A expression that has type dynamic is allowed at compile-time
to be converted to any type; of course you might get a run-time exception.

The default type of a variable would no type-specifier should probably be
'dynamic'.  Of course the implementation type for dynamic is java.lang.Object;
the only difference is static type-checking.  This would actually allow *more*
programs to type-check without warnings than today, which may or may not
be desirable.
--
	--Per Bothner
per@bothner.com   http://per.bothner.com/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]