diff options
Diffstat (limited to 'hack.html.markdown')
| -rw-r--r-- | hack.html.markdown | 629 | 
1 files changed, 351 insertions, 278 deletions
| 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. - - -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. - -```php -<?hh - -// Hack syntax is only enabled for files starting with an <?hh marker -// <?hh markers cannot be interspersed with HTML the way <?php can be. -// Using the marker "<?hh //strict" puts the type checker in strict mode. - - -// Scalar parameter type hints -function repeat(string $word, int $count) -{ -    $word = trim($word); -    return str_repeat($word . ' ', $count); -} - -// Type hints for return values -function add(...$numbers) : int -{ -    return array_sum($numbers); -} - -// Functions that return nothing are hinted as "void" -function truncate(resource $handle) : void -{ -    // ... -} - -// Type hints must explicitly allow being nullable -function identity(?string $stringOrNull) : ?string -{ -    return $stringOrNull; -} - -// Type hints can be specified on class properties -class TypeHintedProperties -{ -    public ?string $name; - -    protected int $id; - -    private float $score = 100.0; - -    // Hack's type checker enforces that typed properties either have a -    // default value or are set in the constructor. -    public function __construct(int $id) -    { -        $this->id = $id; -    } -} - - -// Concise anonymous functions (lambdas) -$multiplier = 5; -array_map($y ==> $y * $multiplier, [1, 2, 3]); - - -// Generics -class Box<T> -{ -    protected T $data; - -    public function __construct(T $data) { -        $this->data = $data; -    } - -    public function getData(): T { -        return $this->data; -    } -} - -function openBox(Box<int> $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<int, Vector<int>>; - -// 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; +[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. + +```Hack +/* ================================== + *           READ THE DOCS! + * ================================== + */ + +/* For more information on the Hack language: + * - About Hack: https://hacklang.org/ + * - Documentation: https://docs.hhvm.com/hack/ + */ + +/* ================================== + *           A NOTE ON PHP + * ================================== + */ + +// The Hack language began as a superset of PHP. +// Since then, the languages have (largely) diverged. +// You may encounter the .php extension, which is no longer recommended. + +/* ================================== + *              COMMENTS + * ================================== + */ + +// Hack has single-line comments... + +/* Multi-line comments... + * + */ + +/** + * ... and a special syntax for doc comments. + * + * Use doc comments to summarize the purpose of a definition, function, class or method. + */ + +/* ================================== + *             NAMESPACES + * ================================== + */ + +// Namespaces contain definitions of classes, interfaces, traits, functions, and constants. + +namespace LearnHackinYMinutes { + +  /* ================================== +   *                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;      } -} - - -// 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<void> -{ -    for ($i = $start; $i <= $end; $i++) { -        echo "$i "; - -        // Give other tasks a chance to do something -        await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0); +    return $result; +  } + +  // Functions can also be anonymous (defined with the `==>` arrow). +  // $f = (int $x): int ==> $x + 1; + +  /* ================================== +   *             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. + +  // 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"; +  } + +  /* ================================== +   *             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<void> { +    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<void> { +    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<void> { +    // 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<T>(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;      } -} - -// 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 get(): int { +      return $this->i;      } +  } -    public function someMethod() -    { -        // ... +  // Properties and Methods can be static (not requiring instantiation). +  class Person { +    public static function favoriteProgrammingLanguage(): string { +      return "Hack";      } -} +  } -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); +  function demo_hack_classes(): void { +    // Use `new` to instantiate a class. +    $c1 = new Counter(); -        // ... -    } +    // To call a static property or method, use `::` +    $typical_person = tuple("Andrew", Person::favoriteProgrammingLanguage()); +  } -    // 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() -    { -        // ... +  // Abstract class can be defined, but not instantiated directly. +  abstract class Machine { +    public function openDoors(): void { +      return;      } -} - -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) -    { -        // ... +    public function closeDoors(): void { +      return;      } - -    // 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-<?hh code" -    // -    <<__Override>> -    public function otherMethod() -    { -        // ... +  } + +  /* ================================== +   *             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 Spaceship extends Machine implements Plane { +    use Airplane; -// Traits can implement interfaces (standard PHP does not support this) -interface KittenInterface -{ -    public function play() : void; -} - -trait CatTrait implements KittenInterface -{ -    public function play() : void -    { -        // ... +    public function fly(): void { +      // fly like the wind      } +  } + +  /* ================================== +   *             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 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 [official HHVM website](http://hhvm.com/) for HHVM installation instructions. +Visit the [Hack language reference](http://docs.hhvm.com/hack/) to learn more about the Hack language. -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/). | 
