learnxinyminutes-docs/hack.html.markdown
Andrew 52cec041d0
Update function names
Follow best practices (function should be snake case [do_task()], and methods should be camel case [doTask()])
2022-07-10 23:06:24 -04:00

12 KiB

language contributors filename
Hack
Andrew DiMola
https://github.com/AndrewDiMola
Stephen Holdaway
https://github.com/stecman
David Lima
https://github.com/davelima
learnhack.hh

Hack lets you write code quickly, while also having safety features built in, like static typechecking.

To run Hack code, install HHVM, the open-source virtual machine.

/* ==================================
 *           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 = process_key($the_answer);

    // Similarily, `num` represents either an int or float.
    $lucky_number = 7;
    $lucky_square = calculate_square($lucky_number);
  }

  function process_key(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;

  /* ==================================
   *             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 do_expensive_task(): ?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;
    }

    public function get(): int {
      return $this->i;
    }
  }

  // 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();

    // To call a static property or method, use `::`
    $typical_person = tuple("Andrew", Person::favoriteProgrammingLanguage());
  }

  // Abstract class can be defined, but not instantiated directly.
  abstract class Machine {
    public function openDoors(): void {
      return;
    }
    public function closeDoors(): void {
      return;
    }
  }

  /* ==================================
   *             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;

    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!
   */
}

More Information

Visit the Hack language reference to learn more about the Hack language.

For more information on HHVM, including installation instructions, visit the official HHVM website.