caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Request for feedback: A problem with injectivity and GADTs
@ 2013-04-28  0:02 Jacques Garrigue
  2013-04-28  2:45 ` Markus Mottl
                   ` (4 more replies)
  0 siblings, 5 replies; 37+ messages in thread
From: Jacques Garrigue @ 2013-04-28  0:02 UTC (permalink / raw)
  To: OCaML List Mailing

Some of you may already be aware of PR#5985
http://caml.inria.fr/mantis/view.php?id=5985

To explain very shortly what is happening, a bug was found in the ocaml
compiler, both 4.00 and the development version, such that one that
convert a value from any type to any other type, bypassing all checks.
This is what we call a soundness bug, a hole in the type system.

Such problems happen at times, and we are usually very fast to fix them.
However this time the problem is bit more subtle, because fixing it
straightforwardly may make impossible to write a whole category of
GADTs. Hence this request for feedback.

Practical description of the problem:

It is quite usual to write type witnesses using a GADT:

type _ ty =
  | Int : int ty
  | Pair : 'a ty * 'b ty -> ('a * 'b) ty
  | Hashtbl : 'a ty * 'b ty -> ('a, 'b) Hashtbl.t ty

This looks fine, but now suppose that we write the following code:

module F (X : sig type 'a t end) = struct
   type _ ty =
    | Int : int ty
    | Pair : 'a ty * 'b ty -> ('a * 'b) ty
    | T : 'a ty -> 'a X.t ty
end

The idea is to create a type witness with the
type constructor X.t instead of Hashtbl.t.
Now I can use it this way:

module U = struct type 'a t = unit end
module M = F(U)
let w = M.T M.Int
(* val w : int U.t M.ty *)
let w' = match w with M.T x -> x | _ -> assert false
(* val w' : '_a M.ty = M.Int *)

What this means is that we can now give an arbitrary type
to a witness for int. You can easily use it to build a function
from int to any  type:

let f : type a. a M.ty -> int -> a =
  fun w x -> match w with M.Int -> x | _ -> assert false;;
let g : int -> float = f w';;

If we look at the source of the problem, it lies in the fact U.t is not injective.
I.e. when we define a GADT, we assume that all the type variables in
the return type can be determined from the type parameter.
That is, from (int U.t M.ty) we assume that the type of the argument of T is (int M.ty).
However, since U.t is not injective, int U.t is actually equal to any type 'a U.t,
and we can convert.
Note that, for known types, injectivity was already checked.
I.e., the following definition is not accepted:

type _ ty =
  | Int : int ty
  | Pair : 'a ty * 'b ty -> ('a * 'b) ty
  | T : 'a ty -> 'a U.t ty

However, abstract types were assumed to be injective.
Here we see that you cannot take this for granted.

The problem is of course not limited to type witnesses, and not even GADTs:
types with constrained parameters (introduced at the very beginning of ocaml),
can also trigger it.
And you don't need a functor to trigger it: once you know that two types are equal
in some scope, there are many ways to leak that information.

=============================
Here comes the request for feedback:

The fix is simple enough: we should track injectivity, and assume that abstract
types are not injective by default.
However, this also means that the first type I defined above (using Hashtbl.t)
will be refused.

How many of you are using GADTs in this way, and how dependent are you on
abstract types ?


If we need to be able to define GADTs relying on the injectivity of some abstract
types, a straightforward solution is to add injectivity annotations on type parameters,
the same way it was done for variance:

  type #'a t

would mean that t is injective.
This is implemented in branches/non-vanishing, in the subversion repository.
	svn checkout http://caml.inria.fr/svn/branches/non-vanishing
Note that in that branch Hashtbl.t in the standard library is marked as injective.
This introduces some new syntax, and libraries have to be modified to benefit,
so the question is do we really need it?


Jacques Garrigue

P.S.
If you are curious about other difficulties of GADTs, the is also branches/abstract-new
which introduces a notion of new types, either concrete or abstract, which are guaranteed
to be distinct from each other, and any other concrete type. This is useful when
checking the exhaustiveness of pattern-matching, as we can then discard impossible
branches. That branch is completely experimental.


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2013-07-05 12:02 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-28  0:02 [Caml-list] Request for feedback: A problem with injectivity and GADTs Jacques Garrigue
2013-04-28  2:45 ` Markus Mottl
2013-04-28 10:28   ` Jacques Garrigue
2013-04-28  5:54 ` Jacques Le Normand
2013-04-29  3:45 ` Ivan Gotovchits
2013-04-29  4:03   ` Ivan Gotovchits
2013-04-29  5:17 ` Jacques Le Normand
2013-04-29  7:58   ` Alain Frisch
2013-04-29 10:52     ` Jacques Garrigue
2013-04-29 11:23       ` Alain Frisch
2013-04-29 16:37         ` Nathan Mishra Linger
2013-04-29 23:53           ` Jacques Garrigue
2013-04-30  5:45       ` Jacques Garrigue
2013-05-04  6:46         ` Jacques Garrigue
2013-05-04  7:09           ` Gabriel Scherer
2013-05-04 12:28             ` Jacques Garrigue
2013-04-30  6:59       ` Alain Frisch
2013-04-30  7:56         ` Jacques Garrigue
2013-04-30  8:02           ` Alain Frisch
2013-04-30  8:18             ` Jacques Garrigue
2013-04-30  9:11               ` Gabriel Scherer
2013-04-30  9:55                 ` Jacques Garrigue
2013-04-30 10:12                   ` Leo White
2013-04-30 11:30                     ` Gabriel Scherer
2013-04-30 13:06                       ` Leo White
2013-04-29  7:59   ` Gabriel Scherer
2013-07-01 14:47 ` Alain Frisch
2013-07-01 23:20   ` Jacques Garrigue
2013-07-03 16:08     ` Alain Frisch
2013-07-03 16:13       ` Gabriel Scherer
2013-07-04  6:07         ` [Caml-list] Request for feedback: A problem with injectivity oleg
2013-07-04  7:35           ` Alain Frisch
2013-07-05 10:30             ` oleg
2013-07-05 12:02               ` Alain Frisch
2013-07-04  1:00       ` [Caml-list] Request for feedback: A problem with injectivity and GADTs Jacques Garrigue
2013-07-04  8:14         ` Alain Frisch
2013-07-04  8:52           ` Jacques Garrigue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).