diff options
Diffstat (limited to 'hack.html.markdown')
-rw-r--r-- | hack.html.markdown | 616 |
1 files changed, 364 insertions, 252 deletions
diff --git a/hack.html.markdown b/hack.html.markdown index fb6af8e1..1ab958b5 100644 --- a/hack.html.markdown +++ b/hack.html.markdown @@ -1,308 +1,420 @@ --- 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. + +```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 + * ================================== + */ -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. +// Namespaces contain definitions of classes, interfaces, traits, functions, and constants. -```php -<?hh +namespace LearnHackinYMinutes { -// 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. + /* ================================== + * TYPES + * ================================== + */ + function demo_hack_types(): void { -// 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; - } -} + // 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); -// Concise anonymous functions (lambdas) -$multiplier = 5; -array_map($y ==> $y * $multiplier, [1, 2, 3]); + // 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); -// Generics -class Box<T> -{ - protected T $data; + // Similarly, `num` represents either an int or float. + $lucky_number = 7; + $lucky_square = calculate_square($lucky_number); + } - public function __construct(T $data) { - $this->data = $data; - } + function process_key(arraykey $the_answer): bool { + if ($the_answer is int) { + return true; + } else { + return false; + } // true + } - public function getData(): T { - return $this->data; - } -} + 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'; + } -function openBox(Box<int> $box) : int -{ - return $box->getData(); -} + // In contrast, an enum class can be of any value type! + enum class Random: mixed { + int X = 42; + string S = 'foo'; + } + + /* ================================== + * HACK ARRAYS + * ================================== + */ + + // The following line lets us use functions in the `C\` namespace. + use namespace HH\Lib\C; // the `C` library operates on containers + + function demo_hack_arrays(): void { + // vec: ordered + $v = vec[1, 2, 3]; + $letters = vec['a', 'b', 'c']; -// 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); + $letters[0]; // returns 'a' + $letters[] = 'd'; // appends 'd' + + // `inout` provides pass-by-reference behavior + C\pop_back(inout $letters); // removes 'd' + C\pop_front(inout $letters); // removes 'a' + + // keyset: ordered, without duplicates + $k = keyset[1, 2, 3]; // values must be int or string + $colors = keyset['red', 'blue', 'green']; + + // keyset keys are identical to their values + $colors['blue']; // returns 'blue'. + + $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]; -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) -); + $alphabet['a']; // indexing at 'a' returns `1` + $alphabet['c'] = 3; // adds a new key-value pair of `c => 3` + unset($alphabet['b']); // removes 'b' + } -// Type aliasing -// -// Hack adds a bunch of type aliasing features for making complex types readable -newtype VectorArray = array<int, Vector<int>>; + /* ================================== + * THE HACK STANDARD LIBRARY (HSL) + * ================================== + */ + + // The Hack Standard Library is a set of functions and classes for the Hack language. + // Namespace use declarations are ideally at the top of your file but are placed here for instruction purposes. + + 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_key($alphabet, 'a'); // checks for a key; returns 'true' + C\contains($alphabet, 'd'); // checks for a value; returns 'false' -// A tuple containing two integers -newtype Point = (int, int); + 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'! + } -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; -} + /* ================================== + * FUNCTIONS + * ================================== + */ + // Functions are defined globally. + // When a function is defined in a class, we refer to the function as a method. -// 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) {} -} + // Functions have return types (here: `int`) and must return a value of + // that type or return no value when a void return type annotation was used. -class WithoutArgumentPromotion -{ - public string $name; + function add_one(int $x): int { + return $x + 1; + } - protected int $age; + // Functions can also have defined, default values. + function add_value(int $x, int $y = 1): int { + return $x + $y; + } - private bool $isAwesome; + // Functions can be variadic (unspecified length of arguments). + function sum_ints(int $val, int ...$vals): int { + $result = $val; - public function __construct(string $name, int $age, bool $isAwesome) - { - $this->name = $name; - $this->age = $age; - $this->isAwesome = $isAwesome; + 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; + + /* ================================== + * PIPE OPERATOR + * ================================== + */ + + // The pipe operator, `|>`, evaluates the result of a left-hand expression + // and stores the result in `$$`, the predefined pipe variable. + + use namespace HH\Lib\Vec; + + function demo_pipe_operator(): void { + + Vec\sort(Vec\map(vec[2, 1, 3], $a ==> $a * $a)); // vec[1,4,9] + + // the same result, but using the pipe operator and pipe variable: + $x = vec[2, 1, 3] + |> Vec\map($$, $a ==> $a * $a) // $$ with value vec[2,1,3] + |> Vec\sort($$); // $$ with value vec[4,1,9] + } + + /* ================================== + * 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>> + async function do_expensive_task(): Awaitable<string> { + $site_contents = await \HH\Asio\curl_exec("http://hacklang.org"); + return $site_contents; + } + + /* ================================== + * 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 requirements 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. + + trait Airplane { + // Introduce a class or interface requirement with the following syntax: + 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/). |