Programação

Técnicas Alternativas de

Cléber Zavadniak

2020

Cléber Zavadniak

  • ~1999: "Apostila de C"
  • 2004: Ciência da Computação, UFPR
  • 2004: C[MCUs] / C++
  • Linux+Networks
  • PHP+MySQL
  • 2013: Python[Django]+MySQL+integrações
  • Python[Django]+Postgres+EDA+Microsserviços+REST
  • Python[Django]+Postgres+RPC+Mezzoserviços+REST
  • Python[Flask]+SQLAlchemy+Postgres+QuasiREST
  • 2020: Go+Postgres+GraphQL

 

https://cleber.solutions/

Apoio:CyberLabs

Apoio: Cyberlabs

Commodities

versus

Valor

Commodity

  • Produto de baixo valor agregado
  • Não sofre processo de alteração
  • Pouco diferenciado

Programação de Commodities

  • Comunicação via HTTP
  • Operações sobre arquivos
  • Interface REST/GraphQL
  • Comunicação com o banco de dados
  • Desktop:
    • Visualizador de imagens
    • Editor de texto plano

Why not X?

  • Why not Rust?
  • Why not Julia?
  • Why not Lua?
    • Você fica meio sem jeito
    • e fica pensando em como responder.
    • Mas no fundo sabe que não tem resposta.
    • Porque não faz diferença, realmente.

 

"Features" de linguagem

importam muito menos que

outras características de ecossistema.

Programação de Valor

  • Sistemas operacionais
  • SGBD
  • Visão computacional
  • Fotogrametria
  • Análise de sinais
  • Cartografia
  • Algoritmos complexos em geral
  • Renderizador de HTML
  • Encoder/decoder de mídia

Why X?

Agora, sim, a pergunta faz sentido.

Commodity != "ruim"

Docker

Sistema Operacional

Seu software

Docker

  • HTTP server/client
  • CLI client
  • Algumas syscalls
  • Manipulação de FS

 

Commodity.

Hardware

C#

Java

JS

Python

Go

PHP

Técnicas Tradicionais

Fortran

COBOL

C++

C

asm

Nem tudo nesse mundo são pregos.

Técnicas Alternativas

Nos trilhos de algumas linguagens

Menções honrosas

LISP

Haskell

Shell Script

Zig

Esqueça tudo, agora.

Prolog

Programação Lógica

Programação Lógica

  • Baseada em... Lógica
    • Basicamente, o estudo estruturado da verdade
    • Entre outras coisas, "cálculo de predicado"
  • Cerne dos programas em Prolog: encontrar a verdade.

Esqueceu tudo?

  • Variáveis
  • Funções
  • Controle de fluxo.

No terminal

swipl -f awesome.pl

swipl -f roads.pl
path(a, e, Path, Distance).
path(a, e, Path, Distance), [H|T] = Path, [H2|T2] = T, H2 = b.

 

append([a], [b], X).

append(A, B, [a, b, c, d]).

 

<vírgula> = AND | <ponto-e-vírgula> = OR/ELSE | <ponto> = END

Vide:

https://medium.com/clebertech-en/prolog-is-not-that-hard-f8cb2b8b3e43
https://medium.com/clebertech-en/prolog-is-not-that-hard-part-2-3a88ac8f02e0

Casos de uso

  • Lógica
  • Análise combinatória
  • Inteligência Artificial
  • Compiladores (semantic checks)
  • Geradores automáticos de testes

 

Exemplo interessante: "julian"

Datas, baseado somente em constraints.

julian

:- use_module(library(julian)).
:- use_module(library(clpfd)).

solution(Year) :-
    % Eisenhower presidency had
    % Fourth of July on Sunday in ...
    form_time([dow(sunday), Year-07-04]),
    Year in 1953..1961.

?- solution(Y).
Y = 1954.

Em outras linguagens

  • Python
    • kanren ("logpy")
  • Go
    • golog
  • Javascript
    • tau-prolog

Erlang

Actor Model

Erlang

Código feito para rodar eternamente.

  • Pattern matching
  • Tail recursion
  • Actor Model

Pattern Matching

Casamento de padrões: herdado do Prolog

(Ver no terminal)

 

{Status, Fd} = file:open(Filename, [read]).
{ok, Fd} = file:open(Filename, [read]).
  • Não existe "atribuição", só casamento de padrão!
  • O binding de valores acontece sempre à esquerda.
  • Também há matching de parâmetros de funções.
X = 10.
10 = X. → Erro!

Tail Recursion

(Recursão no rabo)

Ver no terminal

 

(arquivos.erl+29)

read_line consegue "printar" um arquivo

de qualquer tamanho

sem variação no uso de memória.

 

IMPLEMENTAR: "count.erl"

count(N): printa os números de 0 até N.

Registro de ativação atual

Registro de ativação atual

C

Erlang

Processos

  • Extremamente leves.
    • Cerca de 1,2KB de memória.
    • Per-process Garbage Collection.
  • Todos tem uma "mailbox".
  • Podem ser dependentes entre si.
  • Tail recursion é fundamental.
  • Uma thread da Beam por core.
    • Um scheduler por thread
    • Cada um com sua fila de processamento

 

Ver: processos.erl

Processos != Coroutines

(Ou green threads)

  • Os processos são conhecidos e acessíveis.
    • Pid = spawn(fun).
    • Pid ! message
  • Programação defensiva é desencorajada.
    • Co-rotina falha:
      • Grande problema
      • Difícil de depurar
    • Processo falha:
      • É melhor que morra, mesmo.
      • Dano é contido via "behaviors".

Erlang não é "ultra-rápido"

  • É rápido o bastante.
  • Ser rápido não é o objetivo.
  • O objetivo é rodar eterna e ininterruptamente.

Let it crash!

  • Um componente com problemas não deve afetar os demais.
  • Certos processos são responsáveis por supervisionar outros.
  • Várias "fórmulas" são comuns e são chamadas "behaviors".

Supervisor

(one_to_one)

Supervisor

(one_to_all)

Dict

Dict client

Dict client

Conceitos comuns

  • Let it crash
    • Não trate exceções prematuramente
    • É melhor pedir perdão que permissão
  • Mailboxes
    • EDAs com filas
      • message→SNS→SQS→Worker
      • Kafka/NATS/Rabbit
  • Behaviors
    • Orquestração de serviços

Erlang

Nim

Metaprogramação

Nim

"Tão rápida quanto C,

tão expressiva quanto Python,

tão extensível quanto LISP."

 

  • UFCS
  • Operator overloading
  • Generics
  • Templates
  • Macros

UFCS

  • Unified Function Call Syntax
  • (Presente também na linguagem D)

 

Valores do tipo do primeiro parâmetro de uma função

podem chamá-la com notação similar a

chamada de métodos

(dot notation)

 

Ver no terminal: ufcs.nim

Operator and method overloading

Ver no terminal

Generics

(Ver no terminal)

 

the_minimum(2, 3)

the_minimum[float](2, 3)

Templates

(Ver no terminal: templates.nim)

Templates são macros limitadas

  • Fazem substituições sempre iguais na AST do programa.
  • Ajudam demais em casos extremos de DRY.
    • Como tratadores de erro com `return`.

 

Ver no terminal: templates.nim

Macros

Vide:

https://hookrace.net/blog/introduction-to-metaprogramming-in-nim/

Entendendo a diferença

Se você escrever um `if`...

  • Num template:
    • Nim insere isso onde o template foi chamado
  • Numa macro:
    • Nim interpreta isso em tempo de compilação

Templates versus Macros

Nim

Transpilação

Hardware

CPython

C compiler

Nim Transpiler

Nim

Generated C

Rust

Rust Compiler

Binário

Binário

C

Python

1

2

3

4

Transpilação de Nim

  • Alvos: C, C++, Objective-C e Javascript
  • Permite aproveitar o ecossistema de cada alvo
    • Tudo bem "battle tested"
    • Muita otimização
    • Acompanha novos avanços

E o desempenho?

https://github.com/kostya/benchmarks

https://github.com/drujensen/fib

 

BF = Máquina de Turing.

base64 = encoding.

Havlak = Sei lá. Mas usa várias estruturas de dados.

 

 

Absolutamente recomendado:

https://benchmarksgame-team.pages.debian.net/benchmarksgame/sometimes-people-just-make-up-stuff.html

BF 1

C++ (1s)

Nim GCC (1.75)

Nim Clang (1.78)

C GCC (1.81)

Kotlin (1.87)

 

 

 

 

Resto:

Rust (2.02)

C Clang (2.16)

Go (2.42)

BF 2

C GCC (12s)

Crystal (16s)

C Clang (17s)

C++ (17s)

C# (17s)

Rust (18s)

Nim GCC (18s)

Nim Clang (20s)

Kotlin (21s)

Java (21s)

 

Resto:

Go (40.15)

base64

Rust (1.33s)

C (1.47)

Nim Clang (1.65)

Nim GCC (1.66)

V (~2)

Crystal (2.13)

Ruby (2.17)

Java (2.49)

 

Resto:

Kotlin (2.62)

Node (2.91)

Go (2.93)

Havlak

Crystal (6.90s)

Nim GCC (11.72)

Nim Clang (12.21)

 

 

 

 

 

 

Resto:

C++ (14.20)

Go (18.72)

Min

Programação concatenativa

(M-i-n, não "Nim".)

 

Também Forth, Joy e Cat

Stack based

  • Operações sempre na pilha
  • Pode não haver variáveis

 

"Concatenativa" não significa necessariamente

"stack based". Mas a maioria é.

 

Concatenativa:

Prog_A <concat> ProgB =

Prog_B(Prog_A)

Stack

  • []  # Pilha vazia
  •  
  • 100 → [100]
  • 200 → [100, 200]
  • 300 → [100, 200, 300]
  •  
  • + → [100, 500]
  • * → [50000]

Fatorial

  1. Colocar um valor X na pilha
  2. Chama "factorial"
  3. Atribui o nome "n" ao topo (X)
  4. Põe 1 na pilha
  5. Atribui o nome "i" ao topo (1)
  6. Põe 1 na pilha
  7. Atribui o nome "f" ao topo (1)
  8. Empilha a expressão (i <= n)
  9. Empilha:
    • f = f * i
    • i ++
  10. while (i <= n) {código acima}
  11. Coloca "f" na pilha
 (
   :n
   1 :i
   1 :f
   (i n <=)
   (
     f i * @f 
     i succ @i
   ) while
   f
 ) :factorial
 

But... WHY?

Imagine que

você tem apenas

32 bytes de memória

disponíveis

e precisa executar algoritmos razoavelmente complexos.

Exemplo muito distante?

Argo Submersible Vehicle

Space Shuttle (now retired)

Fim

  • Commodity versus Valor
  • Programação Lógica / Prolog
  • Actor Model / Erlang
  • Metaprogramação / Nim
  • Programação Concatenativa / Min

 

Dedique algum tempo para estudar uma parada ridícula.

 

http://cleber.solutions

Made with Slides.com