Classes

    Assim como outros idiomas orientados a objetos, o Pony tem aulas. Uma classe é declarada com a palavra-chave classe, e tem que ter um nome que comece com uma letra maiúscula, como esta:

class Wombat

    Todos os tipos começam com uma letra maiúscula? Sim! E nada mais começa com uma letra maiúscula. Assim, quando você vê um nome em código Pony, você saberá instantaneamente se é um tipo ou não.

O que acontece em uma classe?

    Uma classe é composta de:

  1. Campos.
  2. Construtores.
  3. Funções.

Campos

    Estes são exatamente como campos em estruturas C ou campos em classes em C++, C#, Java, Python, Ruby, ou basicamente qualquer linguagem, realmente. Há três tipos de campos: var, let, e embed fields. Um campo var pode ser atribuído uma e outra vez, mas um campo let é atribuído no construtor e nunca mais. Os campos embutidos serão cobertos com mais detalhes na documentação sobre variáveis.

class Wombat
  let name: String
  var _hunger_level: U64

    Aqui, um Wombat tem um nome, que é um String, e um _hunger_level, que é um U64 (um inteiro não assinado de 64 bits).
      O que significa o sublinhado principal? Significa que algo é privado. Um campo privado só pode ser acessado por código no mesmo tipo. Um construtor, função ou comportamento privado só pode ser acessado por código no mesmo pacote. Falaremos mais sobre pacotes mais tarde.

    Construtores

      Os construtores em pônei têm nomes. Fora isso, eles são como os construtores em outras linguagens. Eles podem ter parâmetros, e sempre retornam uma nova instância do tipo. Como eles têm nomes, é possível ter mais de um construtor para um tipo. Os construtores são introduzidos com a nova palavra-chave.

    class Wombat
      let name: String
      var _hunger_level: U64
    
      new create(name': String) =>
        name = name'
        _hunger_level = 0
    
      new hungry(name': String, hunger': U64) =>
        name = name'
        _hunger_level = hunger'

      Aqui, temos dois construtores, um que cria um Wombat que não tem fome, e outro que cria um Wombat que pode ter fome ou não. Ao contrário de algumas outras línguas que diferenciam os construtores com sobrecarga de métodos, Pony não presumirá saber qual construtor alternativo invocar com base na aridez e no tipo de seus argumentos. Para escolher um construtor, invoque-o como um método com a sintaxe :

    let defaultWombat = Wombat("Fantastibat") // Invoca o método de criação por padrão
    let hungryWombat = Wombat.hungry("Nomsbat", 12) // Invoca o método com fome("hungry")

        O que é isso da citação única, ou seja, "nome"? Você pode usar aspas simples em nomes de parâmetros e variáveis locais. Em matemática, é chamado de prime, e é usado para dizer "outro destes, mas não o mesmo". Basicamente, é apenas conveniente. Todo construtor tem que definir cada campo em um objeto. Se não o fizer, o compilador lhe dará um erro. Como não há nulo no Pony, não podemos fazer o que Java, C# e muitas outras linguagens fazem e simplesmente atribuir nulo ou zero a cada campo antes que o construtor seja executado, e como não queremos falhas aleatórias, não deixamos campos indefinidos (ao contrário de C ou C++). Às vezes é conveniente definir um campo da mesma maneira para todos os construtores.

      class Wombat
        let name: String
        var _hunger_level: U64
        var _thirst_level: U64 = 1
      
        new create(name': String) =>
          name = name'
          _hunger_level = 0
      
        new hungry(name': String, hunger': U64) =>
          name = name'
          _hunger_level = hunger'

        Aqui, cada Wombat começa um pouco sedento, independentemente de qual construtor é chamado.

      Construtores de Argumento Zero

      class Hawk
        var _hunger_level: U64 = 0
      
      class Owl
        var _hunger_level: U64
      
        new create() =>
          _hunger_level = 42

        Aqui temos duas classes, porque a classe Hawk não define construtores, é gerado um construtor padrão com zero argumentos chamado create. A Coruja define seu próprio construtor que define o nível _hunger_. Ao construir instâncias de classes que têm construtores de zero argumentos, elas podem ser construídas apenas com o nome da classe:

      class Forest
        let _owl: Owl = Owl
        let _hawk: Hawk = Hawk

        Isto é explicado mais tarde, com mais detalhes, na seção de açúcar.

      Funções

        As funções no Pony são como métodos em Java, C#, C++, Ruby, Python, ou praticamente qualquer outra linguagem orientada a objetos. Eles são introduzidos com a palavra-chave diversão. Eles podem ter parâmetros como os construtores têm, e também podem ter um tipo de resultado (se nenhum tipo de resultado for dado, o padrão é Nenhum).

      class Wombat
        let name: String
        var _hunger_level: U64
        var _thirst_level: U64 = 1
      
        new create(name': String) =>
          name = name'
          _hunger_level = 0
      
        new hungry(name': String, hunger': U64) =>
          name = name'
          _hunger_level = hunger'
      
        fun hunger(): U64 => _hunger_level
      
        fun ref set_hunger(to: U64 = 0): U64 => _hunger_level = to

        A primeira função, hunger, é bastante direta. Ela tem um tipo de resultado U64, e retorna _hunger_level, que é um U64. A única coisa um pouco diferente aqui é que nenhuma palavra-chave de retorno é usada. Isto porque o resultado de uma função é o resultado da última expressão na função, neste caso, o valor de _hunger_level.
          Existe uma palavra-chave de retorno no Pony? Sim. Ela é usada para retornar "cedo" de uma função, ou seja, para retornar algo imediatamente e não continuar correndo até a última expressão. A segunda função, set_hunger, introduz um monte de novos conceitos de uma só vez. Vamos analisá-los um a um. A palavra-chave ref logo após a diversão Esta é uma capacidade de referência. Neste caso, significa que o receptor, ou seja, o objeto sobre o qual a função set_hunger está sendo chamada, tem que ser um tipo de ref. Um tipo de ref é um tipo de referência, o que significa que o objeto é mutável. Precisamos disto porque estamos escrevendo um novo valor para o campo _hunger_level.
            Qual é a capacidade de referência do receptor do método hunger? A capacidade de referência padrão do receptor se nenhuma for especificada é caixa, o que significa "Eu preciso ser capaz de ler a partir disto, mas não vou escrever para ele".
              O que aconteceria se deixássemos a palavra-chave ref fora do método set_hunger? O compilador lhe daria um erro. Ele veria que você estava tentando modificar um campo e reclamaria sobre isso.
            • O = 0 após o parâmetro para
            • Este é um argumento padrão. Isso significa que se você não incluir esse argumento no local de chamada, você terá o argumento padrão. Neste caso, será zero se você não o especificar.
            • O que a função retorna?
            • Ela retorna o valor antigo de _hunger_level.
                Espere, sério? O valor antigo? Sim. No Pony, a atribuição é uma expressão e não uma declaração. Isso significa que tem um resultado. Isto é verdade para muitas línguas, mas elas tendem a devolver o novo valor. Em outras palavras, dado a = b, na maioria das línguas, o valor é o valor de b. Mas no Pony, o valor de a é o antigo valor de a.
                  ...por quê? É chamado de "leitura destrutiva", e permite fazer coisas incríveis com um sistema do tipo capabilities-secure. Falaremos sobre isso mais tarde. Por enquanto, vamos apenas mencionar que você também pode usá-lo para implementar uma operação de troca. Na maioria dos idiomas, para trocar os valores de a e b você precisa fazer algo como:

                var temp = a
                a = b
                b = temp

                  Em Pony, você pode simplesmente fazer:

                a = b = a

                Finalizadores

                  Os finalizadores são funções especiais. Eles são nomeados _final, não levam parâmetros e têm uma capacidade de referência do receptor da caixa. Em outras palavras, a definição de um finalizador deve ser fun_final(). O finalizador de um objeto é chamado antes que o objeto seja coletado pelo GC. As funções ainda podem ser chamadas sobre um objeto após sua finalização, mas somente de dentro de outro finalizador. As mensagens não podem ser enviadas de dentro de um finalizador. Os finalizadores são normalmente usados para limpar recursos alocados em código C, como alças de arquivos, soquetes de rede, etc.

                E quanto à herança?

                  Em algumas linguagens orientadas a objetos, um tipo pode herdar de outro tipo, como em Java algo pode estender algo mais. O Pony não faz isso. Em vez disso, Pony prefere a composição à herança. Em outras palavras, em vez de obter a reutilização do código dizendo que algo é algo diferente, você o obtém dizendo que algo tem algo diferente. Por outro lado, Pony tem um poderoso sistema de características (semelhante às interfaces Java 8 que podem ter implementações padrão) e um poderoso sistema de interface (semelhante às interfaces Go, ou seja, estruturalmente digitadas). Falaremos sobre todas essas coisas em detalhes mais tarde.

                Regras de nomenclatura

                  Todos os nomes em Pony, tais como nomes de tipos, nomes de métodos e nomes de variáveis podem conter apenas caracteres ASCII. De fato, todos os elementos do código Pony devem ser ASCII, exceto os caracteres literais, que alegremente aceitam qualquer tipo de bytes diretamente do arquivo fonte, seja ele UTF-8 codificado ou ISO-8859-2 e os representam em sua forma codificada. Um tipo Pony, seja classe, ator, traço, interface, primitivo, ou tipo alias, deve começar com uma letra maiúscula. Após um sublinhado para métodos particulares ou especiais (comportamentos, construtores e funções), qualquer método ou variável, incluindo parâmetros e campos, deve começar com uma letra minúscula. Em todos os casos, os sublinhados em uma linha ou no final de um nome não são permitidos, mas, caso contrário, qualquer combinação de letras e números é legal. De fato, os números também podem usar um único sublinhado no interior como um separador! Somente nomes variáveis podem terminar em sublinhados (').