The Hack Programming Language

Um "novo" PHP

Por ítalo Lelis de Vietro / @italolelis

Quem sou eu




Nascido em Curitiba - PR, mora em João Pessoa a 9 anos.

Arquiteto de Software na Vox Tecnologia
Fundador da Lellys Informática - Agência de desenvolvimento web.

Formado em Análise e Desenvolvimento de Sistemas, atualmente cursando MBA de Engenharia de Software.



Github

Linguagem

Fortemente tipadas






Fracamente tipadas (dinâmicas)







Hack is a language for HHVM that interoperates seamlessly with PHP. The goal of Hack is to offer developers a way to write cleaner, safer and refactorable code while trying to maintain a level of compatibility with current PHP codebases.

O Type Checker

O real valor do Hack




Identifique esses tipos de erros antes


Mesmo quando estiver codando


Type checker robusto

O type checker é o sua melhor linha de defesa.  Contudo, em tempo de execução é permitido coisas que o type checker não aprova.

... perdoando o runtime



Usando o hh_client

O type checker é invocado utilizando o hh_client que vem instalado com o Hack. Esse executável atualmente está disponível apenas para plataformas *nix.

... tenha certeza de procurar o caminho certo

O hh_client varre seus arquivos baseado na localização do arquivo .hhconfig, que nada mais é do que um arquivo vazio. Tenha certeza de te-lo incluido na raiz dos seus projetos.


Tipagem

Type annotations allow for PHP code to be explicitly typed on parameters, class member variables and return values (types are inferred for locals). These annotated types are checked via a type checker.



Parâmetros e retornos tipados


<?hh //strict

function sum(int x, int y): int {
    return x + y;
}



Propriedades tipadas


<?hh //strict

class TestResult
{
    protected int $runCount;

    protected array<Failure> $failures;
}



Closures anotadas


<?hh //strict

function invoke((function(int $x): int) $fn): int {
    return $fn(1);
}


Anotação com o $this


<?hh //strict

class FluentObject
{
    public function doThing(): this
    {
        //do something
        return $this;
    }
}

... ainda precisa de um pouco de trabalho

... podemos fazer um workaround por enquanto

<?hh //strict
namespace HackPack\HackUnit\Runner;

class Options
{
    protected string $testPath;

    /**
     * Use Options type since "this" annotation is broken
     * when namespaces are used
     */
    public function setTestPath(string $testPath): Options
    {
        $this->testPath;
        return $this;
    }
}



O tipo mixed

O type checker do Hack tem algumas maneiras interessantes de lidar com o tipo "mixed", que para muitos programadores PHP é familiar.  O compilador irá identificar quando você tentar validar o tipo.

... precisa ser verificado



<?hh

function sum(mixed $x): void {
  if (is_array($x) || $x instanceof Vector) {
    $s = 0;
    foreach ($x as $v) {
      $s += $v;
    }
    return $s;
  }
  //... do something else or throw an exception...
}
http://docs.hhvm.com/manual/en/hack.annotations.mixedtypes.php



Generators e co-rotinas


O PHP 5.5 trouxe algumas funcionalidades que os programadores já aproveitavam em outras linguagens a anos: generators e coroutines. O Hack tipou essas duas funcionalidades.



Generators tipados

<?hh //strict

function infiniteIterator(): Continuation<int> {
    $i = 0;
    while (true) {
        yield ++$i;
    }
}

Coroutines tipadas


<?hh
async function f(): Awaitable<int> {
  return 42;
}

async function g(): Awaitable<string> {
  $f = await f();
  $f++;
  return 'hi test ' . $f;
}

http://docs.hhvm.com/manual/en/hack.annotations.generators.php



Hack Modes


O compilador do Hack tem vários níveis de tolerância. Eles são conhecidos como modes, e são disparados por comentários.



Strict mode


O nível mais purista. Tudo deve estar tipado e tudo é verificado pelo type checker. Código no modo strict não pode chamar um código que não é escrito em Hack.

... um exemplo do modo strict


<?hh //strict
class TestCase
{
    public function __construct(protected string $name)
    {
    }

    public function setUp(): void
    {
    }

    public function expect<T>(T $context): Expectation<T>
    {
        return new Expectation($context);
    }
}

... strict mode


O modo strict é tão rigoroso que você não poderá ter um ponto de partida no sistema, ou seja, você não pode ter um "main", uma vez que ele estará fora dos padrões strict. Para isso usamos o Partial ou UNSAFE.



Sobre as interfaces hhi


O modo strict irá lançar um erro chamado "Unbound name" quando ele não conseguir encontrar um tipo específico (incluindo funcções). Isso inclui as funções nativas do PHP! Você já pode imaginar como deve ser frustrante chamar sua função favorira do PHP.

... interfaces hhi 


Os arquivos hhi contém interfaces para quase todas as funções do core do PHP. Esses arquivos basicamente disponibilizam informações sobre os tipos de cada função para o compilador do Hack. Você só precisa garantir que eles estejam na raiz do seu projeto.



Um exemplo de interface hhi


Partial mode

Partial mode is the default of Hack. In partial mode, the type checker checks all types other than that encompassed by an // UNSAFE comment. Partial mode also allows for the partially typing of a class, method or function (e.g., only type a subset of its arguments). And, also unlike strict mode, partial mode allows engineers to call code that has not yet been "Hack-ified" (in other words, they can call into untyped code).
http://docs.hhvm.com/manual/en/hack.modes.partial.php

... a melhor aposta para o incio do programa


Ja que o modo strict não permite código de nível superior, o modo parcial é o método para entrada do programa, ou seja o nosso metodo "main".


https://github.com/HackPack/HackUnit/blob/master/bin/Hackunit

Decl mode


Decl mode is used to allow Hack code written in strict mode to call into legacy code, without having to fix the issues that would be pointed out by partial mode. The type checker will "absorb" the signatures of the code, but will not type check the code. Decl is mainly used when annotating old, existing APIs (i.e., when the code does note meet Hack's stricter subset of PHP).

UNSAFE


// UNSAFE disables the type checker from the point of unsafe declaration until the end of the current block of code (where the end of the current block generally refers to the associated ending brace (}) of which the // UNSAFE is declared).
https://github.com/HackPack/HackUnit/blob/master/Runner/Loading/StandardLoader.php#L98

Generics

Hack introduces generics to PHP (in the same vein as statically type languages such as C# and Java). Generics allow classes and methods to be parameterized (i.e., a type associated when a class is instantiated or a method is called).

O maior beneficio e claro: generics podem ser tipos estaticamente. 


Interfaces genéricas são boas para design

<?hh //strict
namespace HackPack\Hacktions;

trait EventEmitter
{
    protected Map<string, Vector<(function(...): void)>> $listeners = Map {};
}
O compilador pode facilmente pode verificar esse tipo de expressão. Dessa forma nosso design fica mais simples.

... o sonho é melhor que a realidade


Enquanto o generics do Hack são tipadas, eles ainda não chegam perto do generics do Java/C#.
Isso ocorre principalmente por que o Hack da a preferencia por inferência e o fato que os tipos não são concretos no Hack.

Inferência


A preferência por inferência parece ser um golpe para a legibilidade. Os seguintes resultados são obtidos por um erro de tipo:

$fun = () ==> { $fn = $this->callable; $fn(); }
$this->expectCallable($fun)->toThrow<ExpectationException>();

//Tests/Core/CallableExpectationTest.php|54 col 70 error|  This operator is not associative, add parentheses

... mas isso funciona


$fun = () ==> { $fn = $this->callable; $fn();};
$this->expectCallable($fun)->toThrow('\HackPack\HackUnit\Core\ExpectationException');

Este trecho também demonstra que não deixaram a "string mágica" padrão do PHP. Tipos não são coisas concretas no Hack - ainda temos de verificar os tipos contra strings.

Generic não se acumulam


Os genéricos não são tão úteis no Hack, porque eles não se acumulam. O que quero dizer com acumular esta descrito na documentação:

A generic method must not collide with any existing, non-generic method name (i.e, public function swap and public function swap).

... mesmo se eles tivessem que ser

<?hh //strict                                
class Cook
{
    use Subject<Waiter>;
    use Subject<Busboy>;
}

//throws type errors
https://github.com/HackPack/Hacktions



Em resumo

Os generics são ferramentas de design realmente úteis. A sua presença no Hack é uma adição bem-vinda, que não está presente no PHP. No entanto, eles não são tão úteis como o são em outras linguagens.

Tipos Nullable

Hack introduces a safer way to deal with nulls through a concept known as the "Nullable" type. Nullable allows any type to have null assigned and checked on it.

http://docs.hhvm.com/manual/en/Hack.nullable.php

Seja explícito sobre a possibilidade de um tipo nulo


<?hh //strict
class Options
{
    protected ?string $HackUnitFile;

    public function getHackUnitFile(): ?string
    {
        $path = (string) getcwd() . '/Hackunit.php';
        if (! is_null($this->HackUnitFile)) {
            $path = $this->HackUnitFile;
        }
        $path = realpath($path);
        return $path ?: null;
    }
}

... não deixe de conferir os tipos nulos


<?hh //strict
class TestResult
{
    protected ?float $startTime;

    public function getTime(): ?float
    {
        $time = null;
        $startTime = $this->startTime;
        $time = microtime(true) - $startTime;
        return $time;
    }

    //TestResult.php|39 col 35 error|  Typing error
    //TestResult.php|39 col 35 error|  This is a num (int/float) because this is used in an arithmetic operation
    //TestResult.php|13 col 15 error|  It is incompatible with a nullable type
}

... isso funciona


<?hh //strict
class TestResult
{
    public function getTime(): ?float
    {
        $time = null;
        $startTime = $this->startTime;
        if (!is_null($startTime)) {
            $time = microtime(true) - $startTime;
        }
        return $time;
    }
}



Em resumo


Nullable permite que você seja explícito sobre a possibilidade de um tipo nulo. Isso torna o código mais legível e mais fácil de se trabalhar.

Collections


Os objetivos das coleções do Hack são 4:
  1. Fornecer um framework que e simples e intuitivo.
  2. Fornecer uma performance igual ou melhor que os arrays do PHP.
  3. Fornecer uma implementação de coleções que permitam tipagem estática, integrando-se com o Hack.
  4. Fornecer uma migração fácil já que foi construído em cima das funcionalidades padrão do PHP5.

Vectors


A Vector is an integer-indexed (zero-based) collection with similar semantics to a C++ vector or a C#/Java ArrayList. Random access to elements happen in O(1) time. Inserts occur at O(1) when added to the end, but could hit O(n) with inserts elsewhere. Removal has similar time semantics.



... um exemplo


Maps


A Map is an ordered dictionary-style collection. Elements are stored as key/value pairs. Maps retain element insertion order, meaning that iterating over a Map will visit the elements in the same order that they were inserted. Insert, remove and search operations are performed in O(lg n) time or better



... um exemplo


Nota: Maps suportam apenas chavez inteiras ou string por enquanto.

Sets


A Set is an ordered collection that stores unique values. Unlike vectors and maps, sets do not have keys, and thus cannot be iterated on keys.



... um exemplo


http://bit.ly/1ntUqVg

Nota: Sets suportam apenas chavez inteiras ou string por enquanto.

Pairs


A Pair is an indexed container restricted to containing exactly two elements. Pair has integer keys; key 0 refers to the first element and key 1 refers to the second element (all other integer keys are out of bounds).



... um exemplo


http://bit.ly/1k08Rhs


Uma nota sobre as coleções imutáveis 


A maioria das coleções do Hack  tem variantes imutáveis ​​- ou seja ImmVector. Coleções Imutáveis ​funcionam como os seus homólogos mutáveis ​​com a ressalva de que os itens não podem ser adicionados ou removidos.



Uma nota sobre array 


As coleções são agora o método preferido de armazenar coisas. Arrays ainda são permitidos, mas devem ser utilizadas de uma nova maneira a estar de acordo com o compilador.

Lambdas


To address the shortcomings of PHP closures, HHVM introduced a "lambda expression" feature. Lambda expressions offer similar functionality to PHP closures, but they capture variables from the enclosing function body implicitly and are less verbose in general.

Tão recente, mas tão limpo


Lambdas deixa códigos dirigido a eventos maravilhosos

$ui = new Text();
$this->runner->on('testFailed', (...) ==> $ui->printFeedback("\033[41;37mF\033[0m"));
$this->runner->on('testPassed', (...) ==> $ui->printFeedback('.'));
https://github.com/HackPack/HackUnit/blob/master/UI/Console.php

Funções de alto nível ficam mais agradáveis de se ver


$squared = array_map($x ==> $x*$x, array(1,2,3));

http://docs.hhvm.com/manual/en/Hack.lambda.examples.php

Uma grande vitória


Isso pode parecer um apenas um pequeno acréscimo, mas é provavelmente uma das melhores características do hack.

$ui = new Text();

$this->runner->on('testFailed', (...) ==> $ui->printFeedback("\033[41;37mF\033[0m"));
//vs
$this->runner->>on('testFailed', function(...) use ($ui) {
   $ui->printFeedback("\033[41;37mF\033[0m";)
});




Perguntas


Obrigado!


italolelis@gmail.com
@italolelis
italolelis.com

Copy of The Hack Programming Language A better way to PHP By Brian Scaturro / @scaturr

By b4d_programmer

Copy of The Hack Programming Language A better way to PHP By Brian Scaturro / @scaturr

  • 710