5

In the Hack language type system, is there a "top" type, also known as an "any" type, or a universal "Object" type? That is, a type which all types are subclasses of?

The manual mentions "mixed" types, which might be similar, but are not really explained. There is also the possibility of simply omitting the type declaration in some places. However, this cannot be done everywhere, e.g. if I want to declare something to be a function from string to the top type, it's not clear how I do this. function (string): mixed?

Charles
  • 50,943
  • 13
  • 104
  • 142
jameshfisher
  • 34,029
  • 31
  • 121
  • 167

1 Answers1

3

I'm an engineer working on Hack at Facebook. This is a really insightful and interesting question. Depending on what exactly you're getting at, Hack has a couple different variations of this.

First, let's talk about mixed. It's the supertype of everything. For example, this typechecks:

<?hh // strict
function f(): mixed {
  return 42;
}

But since it's the supertype of everything, you can't do much with a mixed value until you case analyze on what it actually is, via is_int, instanceof, etc. Here's an example of how you'd have to use the result of f():

<?hh // strict
function g(): int {
  $x = f();
  if (is_int($x)) {
    return $x;
  } else {
    return 0;
  }
}

The "missing annotation" type ("any") is somewhat different than this. Whereas mixed is the supertype of everything, "any" unifies with everything -- it's both the supertype and subtype of everything. This means that if you leave off an annotation, we'll assume you know what you're doing and just let it pass. For example, the following code typechecks as written:

<?hh
// No "strict" since we are omitting annotations
function f2() {
  return 42;
}
function g2(): string {
  return f2();
}

This clearly isn't sound -- we just broke the type system and will cause a runtime type error if we execute the above code -- but it's admitted in partial mode in order to ease conversion. Strict requires that you annotate everything, and so you can't get a value of type "any" in order to break the type system in this way if all of your code is in strict. Consider how you'd have to annotate the code above in strict mode: either f2 would have to return int and that would be a straight-up type error ("string is not compatible with int"), or f2 would have to return mixed and that would be a type error as written ("string is not compatible with mixed") until you did a case analysis with is_int etc as I did in my earlier example.

Hope this clears things up -- if you want clarification let me know in the comments and I'll edit. And if you have other questions that aren't strict clarifications of this, continue tagging them "hacklang" and we'll make sure they get responded to!

Finally: if you wouldn't mind, could you press the "file a documentation bug" on the docs pages that were confusing or unclear, or could in any way be improved? We ideally want docs.hhvm.com to be a one-stop place for stuff like this, but there are definitely holes in the docs that we're hoping smart, enthusiastic folks like yourself will help point out. (i.e., I thought this stuff was explained well in the docs, but since you are confused that is clearly not the case, and we'd really appreciate a bug report detailing where you got lost.)

Josh Watzman
  • 7,060
  • 1
  • 18
  • 26
  • Great answer, thanks! Some clarifications: (1) Every time an annotation is omitted, it is equivalent to `: any`? (2) the `strict` mode is supposed to be sound, but the other modes are intentionally unsound; is this right? It would be great if you guys could publish a white paper describing the type system more formally. It feels like the Hack type system is sufficiently innovative to deserve something like that. Re documentation bugs: will do! – jameshfisher Apr 15 '14 at 14:26
  • 1) A missing annotation is the "any" type, though there is no type `any` that you can explicitly write in your code. 2) The other modes are "intentionally unsound" is one way to put it, but we think of it more as "admit dynamic typing" and "allow delaying type enforcement until runtime" and "allow full untyped PHP interoperability". I'm not sure if we have a plan to write a whitepaper or anything, though maybe we should since lots of folks are interested :) Julien's recent Hack Dev Day talk goes into some internals details in the second half: https://www.youtube.com/watch?v=BnJQJNGkUdM – Josh Watzman Apr 15 '14 at 21:41
  • Re point (1), is that really true? Then what's going on in [this example](http://pastebin.com/wRXJLGQc) which type-checks and runs without error? Is the `any` there being interpreted as you describe above, or as some unknown ordinary type called `any` which somehow doesn't generate a type error? – jameshfisher Apr 16 '14 at 16:28
  • 1
    Make sure you're running the static typechecker `hh_client`! http://docs.hhvm.com/manual/en/install.hack.bootstrapping.php Your code "works" at runtime only since HHVM does not yet enforce generics at runtime. – Josh Watzman Apr 16 '14 at 19:26