diff --git a/hack.html.markdown b/hack.html.markdown
index fb6af8e1..8e2d4b19 100644
--- a/hack.html.markdown
+++ b/hack.html.markdown
@@ -1,308 +1,381 @@
---
language: Hack
contributors:
+ - ["Andrew DiMola", "https://github.com/AndrewDiMola"]
- ["Stephen Holdaway", "https://github.com/stecman"]
- ["David Lima", "https://github.com/davelima"]
filename: learnhack.hh
---
-Hack is a superset of PHP that runs under a virtual machine called HHVM. Hack
-is almost completely interoperable with existing PHP code and adds a bunch of
-useful features from statically typed languages.
+[Hack](https://hacklang.org/) lets you write code quickly, while also having safety features built in, like static typechecking.
+To run Hack code, [install HHVM](https://docs.hhvm.com/hhvm/installation/introduction), the open-source virtual machine.
-Only Hack-specific features are covered here. Details about PHP's syntax are
-available in the [PHP article](http://learnxinyminutes.com/docs/php/) on this site.
+```Hack
+/* ==================================
+ * READ THE DOCS!
+ * ==================================
+ */
-```php
-id = $id;
+ /* ==================================
+ * TYPES
+ * ==================================
+ */
+
+ function demo_hack_types(): void {
+
+ // Hack has five primitive types: bool, int, float, string, and null
+ $is_helpful = true; // bool
+ $int_value = 10; // int
+ $precise_value = 2.0; // float
+ $hello_world = "Hello World!"; // string
+ $null_string = null; // null
+
+ // Create a `shape` with the shape keyword, with a series of field names and values.
+ $my_point = shape('x' => -3, 'y' => 6, 'visible' => true);
+
+ // Create a `tuple` with the tuple keyword, with a series of two or more types as values.
+ $apple_basket = tuple("apples", 25); // different types are OK
+
+ // Use `arraykey` to represent either an integer or string.
+ $the_answer = 42;
+ $is_answer = processKey($the_answer);
+
+ // Similarily, `num` represents either an int or float.
+ $lucky_number = 7;
+ $lucky_square = calculate_square($lucky_number);
+ }
+
+ function processKey(arraykey $the_answer): bool {
+ if ($the_answer is int) {
+ return true;
+ } else {
+ return false;
+ } // true
+ }
+
+ function calculate_square(num $arg)[]: float {
+ return ((float)$arg * $arg);
+ }
+
+ // Enums are limited to int or string (as an Arraykey), or other enum values.
+ enum Permission: string {
+ Read = 'R';
+ Write = 'W';
+ Execute = 'E';
+ Delete = 'D';
+ }
+
+ /* ==================================
+ * HACK ARRAYS
+ * ==================================
+ */
+
+ function demo_hack_arrays(): void {
+
+ // vec: ordered
+ $v = vec[1, 2, 3];
+ $letters = vec['a', 'b', 'c'];
+ $letters[0]; // indexing at `0` returns 'a'
+ $letters[] = 'd'; // appends 'd'
+ // unset($letters['a']); error: remove-at-index is unsupported for vec
+
+ // keyset: ordered, without duplicates
+ $k = keyset[1, 2, 3]; // values must be int or string
+ $colors = keyset['red', 'blue', 'green'];
+ // $colors[0]; error: indexing not supported for keyset
+ $colors[] = 'yellow'; // appends 'yellow'
+ unset($colors['red']); // removes 'red'
+
+ // dict: ordered, by key-value
+ $d = dict['a' => 1, 'b' => 3]; // keys must be int or string
+ $alphabet = dict['a' => 1, 'b' => 2];
+ $alphabet['a']; // indexing at 'a' returns `1`
+ $alphabet['c'] = 3; // adds a new key-value pair of `c => 3`
+ unset($alphabet['b']); // removes 'b'
+ }
+
+ /* ==================================
+ * THE HACK STANDARD LIBRARY (HSL)
+ * ==================================
+ */
+
+ // The Hack Standard Library is a set of functions and classes for the Hack language
+ // Imports are ideally at the top of your file but are placed here for instruction purposes
+
+ use namespace HH\Lib\C; // the `C` library operates on containers (like Hack Arrays)
+ use namespace HH\Lib\Str; // The `Str` library operates on strings
+
+ function demo_hack_standard_library(): void {
+
+ $letters = vec['a', 'b', 'c'];
+ $colors = keyset['red', 'blue', 'green'];
+ $alphabet = dict['a' => 1, 'b' => 2];
+
+ C\contains($letters, 'c'); // checks for a value; returns 'true'
+ C\contains($colors, 'purple'); // checks for a value; returns 'false'
+ C\contains($alphabet, 'a'); // checks for a value; returns 'true'
+
+ Str\length("foo"); // returns `3`
+ Str\join(vec['foo', 'bar', 'baz'], '!'); // returns `foo!bar!baz`
+ }
+
+ /* ==================================
+ * HELLO WORLD!
+ * ==================================
+ */
+
+ use namespace HH\Lib\IO; // the `IO` library is a standard API for input / output
+
+ <<__EntryPoint>> // required attribute for the typical entry/main function
+ async function main(): Awaitable<
+ void,
+ > { // does not need to be named 'main' / is an asynchronous function
+ await IO\request_output()->writeAllAsync(
+ "Hello World!\n",
+ ); // prints 'Hello World'!
+ }
+
+ /* ==================================
+ * FUNCTIONS
+ * ==================================
+ */
+
+ // Functions are defined globally.
+ // When a function is defined in a class, we refer to the function as a method.
+
+ // Functions have return types (here: `int`) and must return a type or nothing (`void`).
+ function add_one(int $x): int {
+ return $x + 1;
+ }
+
+ // Functions can also have defined, default values.
+ function add_value(int $x, int $y = 1): int {
+ return $x + $y;
+ }
+
+ // Functions can be variadic (unspecified length of arguments).
+ function sum_ints(int $val, int ...$vals): int {
+ $result = $val;
+
+ foreach ($vals as $v) {
+ $result += $v;
}
-}
+ return $result;
+ }
+ // Functions can also be anonymous (defined with the `==>` arrow).
+ // $f = (int $x): int ==> $x + 1;
-// Concise anonymous functions (lambdas)
-$multiplier = 5;
-array_map($y ==> $y * $multiplier, [1, 2, 3]);
+ /* ==================================
+ * ATTRIBUTES
+ * ==================================
+ */
+ // Hack provides built-in attributes that can change runtime or static type checking behavior.
+ // For example, we used the `__EntryPoint` attribute earlier in the "Hello World!" example.
-// Generics
-class Box
-{
- protected T $data;
+ // As another example, `__Memoize` caches the result of a function.
+ <<__Memoize>>
+ function doExpensiveTask(): ?string {
+ // return file_get_contents('http://hacklang.org');
+ return "dynamic string with contents from hacklang.org";
+ }
- public function __construct(T $data) {
- $this->data = $data;
+ /* ==================================
+ * CONTEXTS
+ * ==================================
+ */
+
+ // Hack functions are attached to different contexts and capabilities.
+ // A context is a grouping of capabilities; that is, a grouping of permissions.
+
+ // To declare allowed contexts (and capabilities), use the Context List `[]`.
+ // If contexts are not defined, your function includes permissions defined in Hack's `defaults` context.
+
+ // Because the context list is NOT defined, the `defaults` context is implicitly declared.
+ async function implicit_defaults_context(): Awaitable {
+ await IO\request_output()->writeAllAsync(
+ "Hello World!\n",
+ ); // prints 'Hello World'!
+ }
+
+ // In the function below, the context list is defined to have the `defaults` context.
+ // A function can have multiple contexts [context1, context2, ...].
+ // `defaults` includes most of the capabilities defined by the Hack language.
+ async function explicit_defaults_context()[defaults]: Awaitable {
+ await IO\request_output()->writeAllAsync("Hello World!\n");
+ }
+
+ // You can also specify zero contexts to create a pure function (no capabilities).
+ async function empty_context()[]: Awaitable {
+ // The following line is an error, as the function does not have IO capabilities.
+ // await IO\request_output()->writeAllAsync("Hello World!\n");
+ }
+
+ /* ==================================
+ * GENERICS
+ * ==================================
+ */
+
+ // Generics allow classes or methods to be parameterized to any set of types.
+ // That's pretty cool!
+
+ // Hack typically passes by value: use `inout` to pass by reference.
+ function swap(inout T $input1, inout T $input2): void {
+ $temp = $input1;
+ $input1 = $input2;
+ $input2 = $temp;
+ }
+
+ /* ==================================
+ * CLASSES
+ * ==================================
+ */
+
+ // Classes provide a way to group functionality and state together.
+ // To define a class, use the `class` keyword. To instantiate, use `new`.
+ // Like other languages, you can use `$this` to refer to the current instance.
+
+ class Counter {
+ private int $i = 0;
+
+ public function increment(): void {
+ $this->i += 1;
}
- public function getData(): T {
- return $this->data;
+ public function get(): int {
+ return $this->i;
}
-}
+ }
-function openBox(Box $box) : int
-{
- return $box->getData();
-}
-
-
-// Shapes
-//
-// Hack adds the concept of shapes for defining struct-like arrays with a
-// guaranteed, type-checked set of keys
-type Point2D = shape('x' => int, 'y' => int);
-
-function distance(Point2D $a, Point2D $b) : float
-{
- return sqrt(pow($b['x'] - $a['x'], 2) + pow($b['y'] - $a['y'], 2));
-}
-
-distance(
- shape('x' => -1, 'y' => 5),
- shape('x' => 2, 'y' => 50)
-);
-
-
-// Type aliasing
-//
-// Hack adds a bunch of type aliasing features for making complex types readable
-newtype VectorArray = array>;
-
-// A tuple containing two integers
-newtype Point = (int, int);
-
-function addPoints(Point $p1, Point $p2) : Point
-{
- return tuple($p1[0] + $p2[0], $p1[1] + $p2[1]);
-}
-
-addPoints(
- tuple(1, 2),
- tuple(5, 6)
-);
-
-
-// First-class enums
-enum RoadType : int
-{
- Road = 0;
- Street = 1;
- Avenue = 2;
- Boulevard = 3;
-}
-
-function getRoadType() : RoadType
-{
- return RoadType::Avenue;
-}
-
-
-// Constructor argument promotion
-//
-// To avoid boilerplate property and constructor definitions that only set
-// properties, Hack adds a concise syntax for defining properties and a
-// constructor at the same time.
-class ArgumentPromotion
-{
- public function __construct(public string $name,
- protected int $age,
- private bool $isAwesome) {}
-}
-
-class WithoutArgumentPromotion
-{
- public string $name;
-
- protected int $age;
-
- private bool $isAwesome;
-
- public function __construct(string $name, int $age, bool $isAwesome)
- {
- $this->name = $name;
- $this->age = $age;
- $this->isAwesome = $isAwesome;
+ // Properties and Methods can be static (not requiring instantiation).
+ class Person {
+ public static function favoriteProgrammingLanguage(): string {
+ return "Hack";
}
-}
+ }
+ function demo_hack_classes(): void {
+ // Use `new` to instantiate a class.
+ $c1 = new Counter();
-// Co-operative multi-tasking
-//
-// Two new keywords "async" and "await" can be used to perform multi-tasking
-// Note that this does not involve threads - it just allows transfer of control
-async function cooperativePrint(int $start, int $end) : Awaitable
-{
- for ($i = $start; $i <= $end; $i++) {
- echo "$i ";
+ // To call a static property or method, use `::`
+ $typical_person = tuple("Andrew", Person::favoriteProgrammingLanguage());
+ }
- // Give other tasks a chance to do something
- await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0);
+ // Abstract class can be defined, but not instantiated directly.
+ abstract class Machine {
+ public function openDoors(): void {
+ return;
}
-}
-
-// This prints "1 4 7 2 5 8 3 6 9"
-AwaitAllWaitHandle::fromArray([
- cooperativePrint(1, 3),
- cooperativePrint(4, 6),
- cooperativePrint(7, 9)
-])->getWaitHandle()->join();
-
-
-// Attributes
-//
-// Attributes are a form of metadata for functions. Hack provides some
-// special built-in attributes that introduce useful behaviour.
-
-// The __Memoize special attribute causes the result of a function to be cached
-<<__Memoize>>
-function doExpensiveTask() : ?string
-{
- return file_get_contents('http://example.com');
-}
-
-// The function's body is only executed once here:
-doExpensiveTask();
-doExpensiveTask();
-
-
-// The __ConsistentConstruct special attribute signals the Hack type checker to
-// ensure that the signature of __construct is the same for all subclasses.
-<<__ConsistentConstruct>>
-class ConsistentFoo
-{
- public function __construct(int $x, float $y)
- {
- // ...
+ public function closeDoors(): void {
+ return;
}
+ }
- public function someMethod()
- {
- // ...
+ /* ==================================
+ * INTERFACES
+ * ==================================
+ */
+
+ // A class can implement a set of capabilities via an interface.
+ // An interface is a set of method declarations and constants.
+
+ interface Plane {
+ // A constant is a named value. Once defined, the value cannot be changed.
+ const MAX_SPEED = 300;
+ public function fly(): void;
+ }
+
+ /* ==================================
+ * TRAITS
+ * ==================================
+ */
+
+ // A trait defines properties and method declarations.
+ // Traits are recommended when abstracting code for reuse.
+ // Traits are included in code via the `use` keyword.
+ // `use` allows for other includes, like namespaces, classes, and functions (and more)!
+
+ trait Airplane {
+ // Like other languages, classes are extended, and interfaces are implemented.
+ require extends Machine; // abstract class
+ require implements Plane; // interface
+
+ public function takeOff(): void {
+ $this->openDoors();
+ $this->closeDoors();
+ $this->fly();
}
-}
+ }
-class ConsistentBar extends ConsistentFoo
-{
- public function __construct(int $x, float $y)
- {
- // Hack's type checker enforces that parent constructors are called
- parent::__construct($x, $y);
+ class Spaceship extends Machine implements Plane {
+ use Airplane;
- // ...
+ public function fly(): void {
+ // fly like the wind
}
+ }
- // The __Override annotation is an optional signal for the Hack type
- // checker to enforce that this method is overriding a method in a parent
- // or trait. If not, this will error.
- <<__Override>>
- public function someMethod()
- {
- // ...
- }
+ /* ==================================
+ * KEEP READING!
+ * ==================================
+ */
+
+ /* This is a simplified guide!
+ * There's much more to learn, including:
+ * - Asynchronous Operations: https://docs.hhvm.com/hack/asynchronous-operations/introduction
+ * - Reified Generics: https://docs.hhvm.com/hack/reified-generics/reified-generics
+ * - XHP: https://docs.hhvm.com/hack/XHP/setup
+ * - ... and more!
+ */
}
-class InvalidFooSubclass extends ConsistentFoo
-{
- // Not matching the parent constructor will cause a type checker error:
- //
- // "This object is of type ConsistentBaz. It is incompatible with this object
- // of type ConsistentFoo because some of their methods are incompatible"
- //
- public function __construct(float $x)
- {
- // ...
- }
-
- // Using the __Override annotation on a non-overridden method will cause a
- // type checker error:
- //
- // "InvalidFooSubclass::otherMethod() is marked as override; no non-private
- // parent definition found or overridden parent is defined in non->
- public function otherMethod()
- {
- // ...
- }
-}
-
-
-// Traits can implement interfaces (standard PHP does not support this)
-interface KittenInterface
-{
- public function play() : void;
-}
-
-trait CatTrait implements KittenInterface
-{
- public function play() : void
- {
- // ...
- }
-}
-
-class Samuel
-{
- use CatTrait;
-}
-
-
-$cat = new Samuel();
-$cat instanceof KittenInterface === true; // True
-
```
## More Information
-Visit the [Hack language reference](http://docs.hhvm.com/manual/en/hacklangref.php)
-for detailed explanations of the features Hack adds to PHP, or the [official Hack website](http://hacklang.org/)
-for more general information.
+Visit the [Hack language reference](http://docs.hhvm.com/hack/) to learn more about the Hack language.
-Visit the [official HHVM website](http://hhvm.com/) for HHVM installation instructions.
-
-Visit [Hack's unsupported PHP features article](http://docs.hhvm.com/manual/en/hack.unsupported.php)
-for details on the backwards incompatibility between Hack and PHP.
+For more information on HHVM, including installation instructions, visit the [official HHVM website](http://hhvm.com/).