WORK IN PROGRESS ;)
Artigo criado por necessidades práticas no desenvolvimento de aplicativos para dispositivos móveis. Porém, com o tempo, fui adicionando mais linguagens para comparação, migração de código ou interesse histórico. Fui parcialmente inspirado no artigo icônico de Dare Obasanjo comparando C# e Java.
É quase como um Rust vs Go vs C++ vs Swift vs Kotlin vs Java vs C# vs JavaScript vs TypeScript vs Dart vs Python :P Mas também estou começando a comparar duas linguagens funcionais (Lisp e Haskell). Linguagens de mais baixo nível como Web Assembly text format, LLVM e Assembly. Linguagens interpretadas como Ruby e PHP (populares em hospedagens compartilhadas) e VB6 e Smalltalk nessa categoria também. Finalmente, linguagens que de algum modo foram ou ainda são populares como ActionScript, Ada, Objective-C e Object Pascal (Delphi).
Não viu a linguagem que você queria aqui ou gostaria de contribuir com alguma nova linguagem? Esta página é um esforço individual, mas você pode tentar o site colaborativo http://www.rosettacode.org.
Rust - Olá Mundo - main.rs
// requer uma função main
fn main() {
println!("Olá Mundo");
}
Go - Olá Mundo - main.go
// requer um pacote
package main
// requer uma biblioteca para IO
import ("fmt")
// requer uma função main
func main() {
fmt.Println("Olá Mundo")
}
C++ - Olá Mundo - main.cpp
// requer uma biblioteca para IO
#include <iostream>
// requer uma função main na raiz
int main(int argc, const char* argv[]) {
std::cout << "Olá Mundo";
// requer um código de retorno
return 0;
}
Objective-C - Olá Mundo - main.m
// requer uma biblioteca para IO
#import <Foundation/Foundation.h>
// requer uma função main
int main(int argc, const char* argv[]) {
NSLog(@"Olá Mundo");
// requer um código de retorno
return 0;
}
Swift - Olá Mundo - main.swift
print("Olá Mundo")
Kotlin - Olá Mundo - main.kt
// requer uma função main
fun main(args: Array<String>) {
println("Hello, world!")
}
Java - Olá Mundo - OlaMundo.java
// Java 21+
void main() {
System.out.println("Olá Mundo");
}
// Java 20-
public class OlaMundo {
// requer um método estático main em uma classe
public static void main(String[] args) {
System.out.println("Olá Mundo");
}
}
C# - Olá Mundo - OlaMundo.cs
// C# 9+
System.Console.WriteLine("Olá Mundo");
// C# 8-
public class OlaMundo {
// requer um método estático main em uma classe
public static void Main(string[] args) {
System.Console.WriteLine("Olá Mundo");
}
}
Dart - Olá Mundo - main.dart
// requer uma função main
void main() {
print('Olá Mundo');
}
TypeScript - Olá Mundo - main.ts
console.log('Olá Mundo')
JavaScript - Olá Mundo - main.js
console.log('Olá Mundo')
ActionScript - Olá Mundo - main.as
trace('Olá Mundo')
Python - Olá Mundo - main.py
print('Olá Mundo')
PHP - Olá Mundo - index.php
<?= 'Olá Mundo' ?>
ou
<?php echo 'Olá Mundo' ?>
ou
<?php echo <<<'EOD'
Olá Mundo
EOD; ?>
embora o primeiro código que você
vai escrever provavelmente seja
<?php phpinfo(); ?>
VBA / VB6 - Olá Mundo - main.bas
Debug.Print "Olá Mundo"
Ada - Olá Mundo - main.adb
-- requer uma biblioteca para IO
with Ada.Text_IO; use Ada.Text_IO;
-- requer uma função main
-- mas pode ter um nome diferente
procedure Main is
begin
Put_Line("Olá Mundo");
end Main;
Object Pascal (Delphi) - Olá Mundo - main.dpr
// requer uma função main
// mas pode ter um nome diferente
program Main;
begin
WriteLn('Olá Mundo');
end.
Ruby - Olá Mundo - main.rb
puts "Olá Mundo"
SmallTalk - Olá Mundo - main.st
Transcript show: 'Olá Mundo'.
Common Lisp - Olá Mundo - main.lisp
(print "Olá Mundo")
; ou para retornar uma string do programa
"Olá Mundo"
Haskell - Olá Mundo - main.hs
putStrLn "Olá Mundo"
-- ou para retornar uma string do programa
"Olá Mundo"
F#
printfn "Olá Mundo"
Web Assembly text format - main.wasm
(module
;; web assembly does not interact with the DOM
;; so we must import certain browser functions
(import "console" "log" (func $log (param i32 i32)))
(import "js" "mem" (memory 1))
(data (i32.const 0)
"Hello World"
)
(func (export "main")
i32.const 0 ;; pass offset 0 to log
i32.const 11 ;; pass length 11 to log
call $log
)
)
JavaScript
let memory = new WebAssembly.Memory({ initial: 1 });
// object to be imported by web assembly
let importObject = {
console: {
// web assembly can only send numbers and bytes
// so it requires a special console.log
log: function(offset, length) {
var bytes = new Uint8Array(memory.buffer, offset, length);
var string = new TextDecoder('utf8').decode(bytes);
console.log(string);
}
},
js: {
mem: memory
}
};
WebAssembly
.instantiateStreaming(
fetch('main.wasm'),
importObject
)
.then(obj => {
obj.instance.exports.main();
});
LLVM IR
source_filename = "main"
; requer uma função externa para IO
declare i32 @puts(i8* nocapture) nounwind
@helloWorld = private constant [10 x i8] c"Olá Mundo\00"
; requer um bloco main
define void @main() {
entry:
%cast210 = getelementptr [10 x i8], [10 x i8]* @helloWorld, i64 0, i64 0
call i32 @puts(i8* %cast210)
; requer um código de retorno TODO testar
ret i32 0
}
Assembly
section .text
global _start ; requer um bloco "main"
_start:
call io
call exit
io:
; requer um system call para IO
mov eax, system_interrupt_write
mov ebx, standard_output
mov ecx, message
mov edx, message_length
int system_call_interrupt
ret
exit:
; requer um código de retorno
mov eax, system_interrupt_exit
int system_call_interrupt
ret
section .data
; dados do programa
message db 'Olá Mundo', 0xa
message_length equ $ - message
; dados padrões do sistema
standard_output equ 1
system_interrupt_write equ 4
system_interrupt_exit equ 1
system_call_interrupt equ 0x80
Python e Swift são as mais simples de todas.
Nem ;
elas precisam, e seu uso nem é recomendado no caso do Swift.
Curioso encontrar VB6 aqui na mesma posição.
JavaScript perde por pouco.
Também não requer ;
embora ao contrário do que ocorre com Swift, seu uso seja recomendado.
Seu console.log
também é um pouco maior que o método print
.
C# 9+ vem logo atrás, pois tem mais um namespace a ser digitado antes da função.
PHP foi criado para ser utilizado em conjunto com HTML, e por isso requer tags para abrir e fechar os blocos de código.
Possui uma tag de atalho para casos simples e uma alternativa para textos longos, que acho confusa e pessoalmente nunca vi ser usada.
Usos mais complexos tendem a utilizar frameworks ou mecanismos de template
Rust ainda requer uma função main
, mas o retorno dela não precisa ser declarado explicitamente.
Diferente das demais linguagens, usa um macro para IO, por isso print!
leva uma exclamação (não, não era porque eu estava entusiasmado quando escrevi o código).
Dart, Kotlin e Object Pascal (Delphi) tem uma ou outra coisa a mais qua deve ser digitada a mais do qua Rust.
Object Pascal (Delphi), assim como Ada e VB6 utilizam mais palavras reservadas do que símbolos.
C# 8- e Java são idênticos, ambos requerendo uma classe que contenha o método main
.
Sentiu uma leve pressão para escrever orientado a objeto aqui?
Também é recomendado que o nome do arquivo tenha o mesmo nome da classe.
Go é quase tão comprido quanto C++ e Objective-C.
Não requer que a função main
retorne um inteiro, mas requer um pacote.
Ada
C++ e Objective-C são bastante parecidos pois possuem forte influência do C.
LLVM IR TODO
Assembly é completamente diferente dos demais. Se bem organizado para este exemplo simples, até fica bastante legível, embora verboso.
A ordem invertida dos argumentos e nome da função é pouco intuitiva.
Web Assembly text format
Rust
Nativa compiladaGo
Nativa compiladaC++
Nativa compiladaObjective-C
Nativa compiladaSwift
Nativa compiladaKotlin
Process virtual machineJava
Process virtual machine (JVM)C#
Process virtual machine (CLR)Dart
TypeScript
É transcompilada para JavaScriptJavaScript
Interpretada + Just in time compilerActionScript
Process virtual machine (AVM2)Python
Interpretada (versão oficial sem just in time compiler)PHP
Versões mais novas usams Zend Virtual Machine, mas o código é recompilado a cada execuçãoVBA / VB6
Nativa compiladaAda
Nativa compiladaObject Pascal (Delphi)
Nativa compiladaRuby
Process virtual machine (YARV)Smalltalk
InterpretadaCommon Lisp
InterpretadaHaskell
Nativa compilada via GHC (realiza transpilação, depois compilação) ou interpretadaF#
Process virtual machine (CLR)Web Assembly text format
Stack based vmLLVM IR
Instruções baixo nível que serão compiladasAssembly
Nativa compiladaA
Rust
// linha
/*
bloco
*/
fn someFunction(/* bloco */ arg1:i32) -> i32 {
0
}
Go
// linha
/*
bloco
*/
func someFunction(/* bloco */ x int) int {
return 0
}
C++
// linha
/*
bloco
*/
int someFunction(/* bloco */ int arg) {
return 0;
}
Objective-C
// linha
/*
bloco
*/
int someFunction(/* bloco */ int arg) {
return 0;
}
@implementation SomeClass
- (int) someMethod /* bloco */ :(int)arg {
return 0;
}
@end
Swift
// linha
/*
bloco
*/
func someFunction(/* bloco */ arg1:Int) -> Int {
return 0
}
Kotlin
// linha
/*
bloco
*/
fun someFunction(/* bloco */ arg:Int): Int {
return 0
}
Java
// linha
/*
bloco
*/
int someMethod(/* bloco */ int arg) {
return 0;
}
C#
// linha
/*
bloco
*/
int someFunction(/* bloco */ int arg) {
return 0;
}
Dart
// linha
/*
bloco
*/
int someFunction(/* bloco */ int arg) {
return 0;
}
TypeScript
// linha
/*
bloco
*/
function someFunction(/* bloco */ arg:number):number {
return 0;
}
JavaScript
// linha
/*
bloco
*/
function someFunction(/* bloco */ arg) {
return 0;
}
ActionScript
// linha
/*
bloco
*/
function someFunction(/* bloco */ arg:int):int {
return 0;
}
Python
# linha
"""
string sendo usada como comentário de bloco
"""
# Django also
# supports {# your comment #}
# and {% comment "your comment" %}
# as a block comment
PHP
// linha
# linha
/*
bloco
*/
function someFunction(/* bloco */ int $arg):int {
return 0;
}
VBA / VB6
' linha
Ada
-- linha
Object Pascal (Delphi)
// linha
{
bloco
}
(*
bloco
*)
Ruby
# linha
=begin
bloco
o end precisa ocupar
uma linha separada
=end
# ruby on rails also
# supports <%# comment %>
# as a block comment
Smalltalk
"bloco"
Common Lisp
; linha
#|
bloco
|#
Haskell
-- linha
{-
bloco
-}
F#
// linha
(*
bloco
*)
let someFunction (* bloco *) _x =
0
Web Assembly text format
;; linha
LLVM IR
; linha
Assembly
; linha
Rust
/*
bloco
/*
bloco aninhado
*/
bloco
*/
Go
-C++
-Objective-C
-Swift
/*
bloco
/*
bloco aninhado
*/
bloco
*/
Kotlin
-Java
-C#
-Dart
/*
bloco
/*
bloco aninhado
*/
bloco
*/
TypeScript
-JavaScript
-ActionScript
-Python
-PHP
-VBA / VB6
-Ada
-Object Pascal (Delphi)
// Turbo Pascal and Delphi do not support
// Free Pascal supports it
// better not use
Ruby
-Smalltalk
-Common Lisp
#|
bloco
#|
bloco aninhado
|#
bloco
|#
Haskell
{-
bloco
{-
bloco aninhado
-}
bloco
-}
F#
-Web Assembly text format
-LLVM IR
-Assembly
-Rust
// region idea intellij foldable
// endregion
Go
// TODO talvez seja suportado
// por GoLand ou extensão
// do VS Code
C++
#pragma region vscode foldable
#pragma endregion
Objective-C
#pragma mark - XCode section with dash
#pragma mark XCode section
Swift
// MARK: - XCode section with dash
// MARK: XCode section
Kotlin
// region idea intellij foldable
// endregion
Java
// region idea intellij foldable
// endregion
// #region vs code foldable
// #endregion
C#
#region foldable
#endregion
Dart
// region idea intellij foldable
// endregion
// #region vs code foldable
// #endregion
TypeScript
// #region vs code foldable
// #endregion
JavaScript
// #region vs code foldable
// #endregion
ActionScript
// Adobe Animate/Flash and FlashDevelop
// are able to collapse any scope or
// selected portions of the source code
// #region vs code foldable
// #endregion
Python
#region foldable (pycharm, visual studio and vs code)
#endregion
PHP
VBA / VB6
#Region vs code foldable
#End Region
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Documentação de folding do VS Code.
Rust
/// Rustdoc para o item que segue **com markdown**
/// # Arguments
/// * `arg1` - The argument of the function
/// # Examples
/// ```
/// let result = some_function(2);
/// ```
fn some_function(arg1:i32) -> i32 {
0
}
mod foo {
//! Rustdoc para o contêiner externo
}
Go
// someFunction Comentários simples logo antes das declarações
func someFunction(/* bloco */ x int) int {
return 0
}
C++
/// <summary>Visual Studio XML Documentation alt 1</summary>
/// <param>The argument of the function</param>
/// <returns>The result of the function call</returns>
/// <example>
/// <code>
/// auto result{someFunction(2)};
/// </code>
/// </example>
int someFunction(int arg) {
return 0;
}
/**
<summary>Visual Studio XML Documentation alt 2</summary>
<param>The argument of the function</param>
<returns>The result of the function call</returns>
<example>
<code>
auto result{someFunction(2)};
</code>
</example>
*/
int someFunction(int arg) {
return 0;
}
/// XCode Doxygen / Header Doc alt 1
/// \param arg The argument of the function
/// \returns The result of the function call
/// \code
/// auto result{someFunction(2)};
int someFunction(int arg) {
return 0;
}
//! XCode Doxygen / Header Doc alt 2
//! @param arg The argument of the function
//! @return The result of the function call
//! @code
//! auto result{someFunction(2)};
int someFunction(int arg) {
return 0;
}
/**
XCode Doxygen / Header Doc alt 3
\param arg The argument of the function
\return The result of the function call
\code
auto result{someFunction(2)};
*/
int someFunction(int arg) {
return 0;
}
/*!
XCode Doxygen / Header Doc alt 4
@param arg The argument of the function
@returns The result of the function call
@code
auto result{someFunction(2)};
*/
int someFunction(int arg) {
return 0;
}
Objective-C
// C style
/// XCode Doxygen / Header Doc alt 1
/// \param arg The argument of the function
/// \returns The result of the function call
/// \code
/// int result = someFunction(2);
int someFunction(int arg) {
return 0;
}
//! XCode Doxygen / Header Doc alt 2
//! @param arg The argument of the function
//! @return The result of the function call
//! @code
//! int result = someFunction(2);
int someFunction(int arg) {
return 0;
}
/**
XCode Doxygen / Header Doc alt 3
\param arg The argument of the function
\return The result of the function call
\code
int result = someFunction(2);
*/
int someFunction(int arg) {
return 0;
}
/*!
XCode Doxygen / Header Doc alt 4
@param arg The argument of the function
@returns The result of the function call
@code
int result = someFunction(2);
*/
int someFunction(int arg) {
return 0;
}
// Objective-C style
@implementation SomeClass
/// XCode Doxygen / Header Doc alt 1
/// \param arg The argument of the function
/// \returns The result of the function call
/// \code
/// SomeClass *someObject = [SomeClass alloc];
/// int result = [someObject someMethod:2];
- (int) someMethod /* bloco */ :(int)arg {
return 0;
}
//! XCode Doxygen / Header Doc alt 2
//! @param arg The argument of the function
//! @return The result of the function call
//! @code
//! SomeClass *someObject = [SomeClass alloc];
//! int result = [someObject someMethod:2];
- (int) someMethod /* bloco */ :(int)arg {
return 0;
}
/**
XCode Doxygen / Header Doc alt 3
\param arg The argument of the function
\return The result of the function call
\code
SomeClass *someObject = [SomeClass alloc];
int result = [someObject someMethod:2];
*/
- (int) someMethod /* bloco */ :(int)arg {
return 0;
}
/*!
XCode Doxygen / Header Doc alt 4
@param arg The argument of the function
@returns The result of the function call
@code
SomeClass *someObject = [SomeClass alloc];
int result = [someObject someMethod:2];
*/
- (int) someMethod /* bloco */ :(int)arg {
return 0;
}
@end
Swift
/**
XCode markdown
- Parameter arg1: The argument of the function
- Returns: The result of the function call
let result = someFunction(2)
*/
func someFunction(arg1:Int) -> Int {
return 0
}
Kotlin
/**
KDoc
{@code
var result = someFunction()
}
@param arg1 The argument of the function
@return The result of the function call
*/
fun someFunction(arg1:Int):Int {
return 0
}
Java
public class SomeClass {
/**
JavaDoc
{@code
SomeClass someObject = new SomeClass();
int result = someObject.someMethod();
}
@param arg1 The argument of the function
@return The result of the function call
*/
public int someMethod(int arg1) {
return 0;
}
}
C#
public class SomeClass {
/// <summary>Visual Studio XML Documentation alt 1</summary>
/// <param name="arg1">The argument of the function</param>
/// <returns>The result of the function call</returns>
/// <example>
/// <code>
/// var someObject = SomeClass();
/// var result = someObject.SomeMethod(2);
/// </code>
/// </example>
public int SomeMethod(int arg1) {
return 0;
}
/**
<summary>Visual Studio XML Documentation alt 2</summary>
<param name="arg1">The argument of the function</param>
<returns>The result of the function call</returns>
<example>
<code>
var someObject = SomeClass();
var result = someObject.SomeMethod(2);
</code>
</example>
*/
public int SomeOtherMethod(int arg1) {
return 0;
}
}
Dart
/// To reference parameter names
/// in the comment we use square
/// brackets [arg1] and unstructured
/// text.
///
/// Markdown is supported, particularly,
/// examples use triple backtics
/// ```dart
/// min(5, 3) == 3
/// ```
int someFunction(int arg1) {
return 0;
}
TypeScript
JavaScript
/**
JSDoc
@param {number} arg1 The argument of the function
@returns {number} The result of the function call
@example
let result = someFunction(2);
*/
function someFunction(arg1) {
return 0;
}
/**
para indicar overloads, usamos uma mistura de tipos
e argumentos opcionais que fica com uma péssima
legibilidade
@param {(number|string)} arg1 número ou string
@param {number} [arg2] opcional
@returns {(number|string)} número ou string
para cobrir a falta de suporte da linguagem para
certas funcionalidades, podemos usar também
@private, @override, @enum etc.
*/
function someFunction(arg1) {
/// <signature>
/// <summary>Visual Studio XML Documentation</summary>
/// <param name="arg1" type="Number">The argument of the function</param>
/// <returns type="Number">The result of the function call</returns>
/// </signature>
return 0;
}
// <signature> é opcional, e permite separar claramente
// os overloads da função, pois podemos ter mais de uma signature
ActionScript
/**
* ASDoc
* <p>Html such as <code>myMethod</code> is allowed.
* Notice that you do not use the paragraph tag in the
* first paragraph of the description.</p>
*
* @param arg1 The argument of the function
* @return The result of the function call
* @see someOtherMethod
*/
function someFunction(arg1:int):int {
return 0;
}
Python
some_function.__doc__ = ".__doc__ guarda um texto de ajuda"
def some_function(arg1: int):
"""Ou então logo após a linha de definição.
If the argument `sound` isn't passed in, the default Animal
sound is used.
Parameters
----------
arg1 : int
Primeiro argumento
"""
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Objective-C, Swift e C# possuem ferramentas padrão nas respectivas IDEs.
C++ não possui uma ferramenta oficial. Varia de acordo com a IDE ou ferramenta externa e permite a mistura de muitos estilos e palavras alternativas.
Rust possui documentação inline padronizada, mas as possibilidades são bastante simples.
Java usa JavaDoc, que só permite documentação usando /** */
. Aliado com o fato de que Java não suporta comentários de bloco aninhados, um trecho de código devidamente documentado é impossível de se comentar com /* */
.
JavaScript, assim como C++ não possui padrão de documentação. Porém, o caso do JavaScript é mais grave pois as sintaxes variam bastante entre si, inclusive quanto ao seu posicionamento no código. A ferramenta mais amplamente difundida JSDoc possui sintaxe confusa quanto à overloads.
Rust
let x = 5; // tipo implícito
let x:i32 = 5; // tipo explícito
let mut x = 5; // variável
let x = 5; // constante
let a:i32 = 1;
let ponteiro_de_int_const:*const i32 = &a;
let mut b:i32 = 1;
let ponteiro_de_int_var:*mut i32 = &mut b;
Go
var x = 5 // tipo implícito
var x int32 = 5 // tipo explícito
x := 5 // atalho para declaração
const x = 5 // constante
var a = 1
var ponteiroDeInt *int = &a // ponteiro
// variáveis relacionadas
// podem ser declaradas juntas
var (
countLock sync.Mutex
inputCount uint32
outputCount uint32
errorCount uint32
)
C++
auto x{5}; // tipo implícito
int x{5}; // tipo explícito
int x(5); // estilo antigo
int x = 5; // estilo c
const int z{5}; // constante
constexpr int x{5}; // expressão constante
int& referenciaDeInt; // referência
int* ponteiroDeInt{&x}; // ponteiro
Objective-C
int x = 5; // variável
const int x = 5; // constante
int* x; // ponteiro
Swift
let x = 5 // tipo implícito
let x:Int = 5 // tipo explícito
var x = 5 // variável
let x = 5 // constante
// Swift tem lazy properties declaradas com
// lazy var x = ...
// veja classes para exemplos dessa declaração
Kotlin
val x = 5 // tipo implícito
val x:Int = 5 // tipo explícito
var x = 5 // variável
val x = 5 // constante
// não precisa ser inicializada na declaração
val x:Int
x = 5
// constante em tempo de compilação
// precisa ser inicializada na declaração
const val x = 5
Java
var x = 5; // tipo implícito - java 10+
int x = 5; // tipo explícito
int x = 5; // variável
final int x = 5; // constante
// não precisa ser inicializada na declaração
final int x;
x = 5;
C#
var x = 5; // tipo implícito
int a = 5; // tipo explícito
var x = 5; // variável
const int x = 5; // constante
// tipo ignorado em tempo de compilação
dynamic x = 5;
unsafe {
int* ponteiroDeInt = &x; // ponteiro
}
Dart
var x = 5 // tipo implícito
int x = 5 // tipo explícito
int x = 5; // variável
final int x = 5; // assign only once constant
const int x = 5; // compile time constant
// não precisa ser inicializada na declaração
final int x;
x = 5;
// lazy
late int x = expensiveCall();
TypeScript
JavaScript
'use strict';
let x = 5; // variável
const x = 5; // constante
let x = 5; // tipo dinâmico
var x = 5; // estilo antigo
// lança exceção em modo estrito
// mas é aceito em modo normal
useSemDeclarar = 5;
ActionScript
var x = 5; // tipo dinâmico
x = 'dynamic type';
var x:int = 5; // tipo explícito
const x = 5; // constante
const x:int = 5; // constante
Python
# não existe uma declaração explícita
# erros de digitação podem introduzir bugs
# indesejados...
x = 5
x = 'dynamic type'
x:int = 5
PHP
// não existe uma declaração explícita
// erros de digitação podem introduzir bugs
// indesejados...
$x = 5; // variável
const x = 5; // constante
define('x', '5'); // constante
$referenciaDeX =&$x; // referência
global $g; // variável global
// variáveis Variáveis
$Bar = "a";
$Foo = "Bar";
$World = "Foo";
$Hello = "World";
$a = "Hello";
$a; // retorna Hello
$$a; // retorna World
$$$a; // retorna Foo
$$$$a; // retorna Bar
$$$$$a; // retorna a
$$$$$$a; // retorna Hello
$$$$$$$a; // retorna World
VBA / VB6
Option Explicit
Dim x As Integer: x = 5 ' variável
Const x As Integer = 5 ' constante
Dim x: x = 5 ' tipo dinâmico
Dim x As Variant: x = 5 ' tipo dinâmico
' lança exceção com Option Explicit
' caso contrário é aceito
useSemDeclarar = 5
' Datas tem uma literal especial, em formato americano...
' Podemos digitar no formato #yyyy-mm-dd# e a IDE troca automaticamente para nós
Const dataLimite As Date = #12/30/2017#
Ada
procedure Main is
-- variáveis são declaradas
-- num bloco separado
X:Integer := 0; -- variável
Y:constant Integer := 0; -- constante
begin
-- variáveis são declaradas
-- num bloco separado
declare
Y:Integer := 0;
begin
null;
end;
end Main;
Object Pascal (Delphi)
program Main;
// variáveis são declaradas
// num bloco separado
var x:Integer = 0; // variável
const y:Integer = 0; // constante
begin
//
end.
Ruby
# não existe uma declaração explícita
# erros de digitação podem introduzir bugs
# indesejados...
x = 0 # variável
X = 0 # constante (maiúscula, lança warning apenas)
Smalltalk
"variáveis são declaradas"
"num bloco separado?"
|x|
x := 5
Common Lisp
; variáveis
(let(
(x 0)
(y 0)
z
))
(let*(
(x 0)
(y 0)
z
))
(defvar *x* 0)
(defparameter *x* 0.001)
; constante
(defconstant x 0 "constante")
Haskell
x <- return 0 -- variável
x = 0 -- constante
let x = 0 -- constante
{-
identificadores são declarados
num bloco separado where
se o escopo for local
Além disso, como os identificadores
nunca mudam de valor, a declaração
pode ser feita depois do seu uso
-}
minhaFuncao paramA = paramA * valorB
where
-- valorB declarado depois
valorB = paramA + 1
F#
let x = 0 // constante
Web Assembly text format
(module
(memory $0 0)
i32.const 0
)
LLVM IR
Assembly
Rust
let (x, y) = (1, 2);
Go
// não suporta, mas as funções
// podem retornar valores múltiplos
min, max := getBounds(points)
C++
// C++ 17+
auto [x, y] = std::make_tuple(1, 2);
struct Point {
int x;
int y;
};
Point p {1, 2};
auto [x, y] = p;
Objective-C
-Swift
let (x, y) = (1, 2)
Kotlin
var (x, y) = Pair(1, 2)
Java
-C#
// C# 7+
(var x, var y) = (1, 2);
// TODO deconstructors
Dart
// check progress
TypeScript
JavaScript
[x, y] = [1, 2];
ActionScript
-
Python
x, y = (1, 2)
head, *tail = [1, 2, 3, 4, 5]
a, b, *other, z = [1, 2, 3, 4, 5]
a, _ = [1, 2]
print(a)
# Prints: 1
a, _, c = (1, 2, 3)
print(a)
# Prints: 1
print(c)
# Prints: 3
a, *_ = [1, 2, 3, 4, 5]
a, *_, b = [1, 2, 3, 4, 5]
a, _, b, _, c, *_ = [1, 2, 3, 4, 5, 6]
PHP
// list() style
list($x, $y) = [1, 2];
// [] style
[$x, $y] = [1, 2];
VBA / VB6
-Ada
-Object Pascal (Delphi)
-Ruby
x, y = 1, 2
Smalltalk
Common Lisp
(destructuring-bind (x y) (list 1 2)
;...
)
Haskell
-F#
Web Assembly text format
LLVM IR
Assembly
Rust
let eu1:i32;
let _ = "bem sucinto";
let _123 = "meio confuso";
let _if = "meio confuso";
// podemos ainda usar r# na frente
// do nome pra evitar colisões
// com palavras-chave e tipos
let r#if = "muito confuso";
let r#int = "muito confuso";
// a diferença de r# ao invés de _
// é que r# foi introduzido para
// suportar códigos de edições anteriores
// por exemplo, a palavra-chave try
// foi criado na edição 2018,
// invalidando a macro try! da edição 2015
// que pode ser chamada com r#try! se necessário
Go
var _123 = 1
var _if = 1
var π = 3.14159
var 你好 = "你好世界"
// letras unicode, números e _
C++
int eu1;
auto _ = "bem sucinto";
auto _123 = "meio confuso";
auto _if = "meio confuso";
Objective-C
int eu1;
int _ = "bem sucinto";
int _123 = "meio confuso";
int _if = "meio confuso";
Swift
// TODO
// ignorar a variável
let _ = 1
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
// cannot contain
// whitespace characters
// mathematical symbols
// arrows
// private-use (or invalid)
// Unicode code points
// line- and box-drawing
// cannot begin with a number
Kotlin
Java
int eu1;
int _ = "bem sucinto"; // deprecated
int _123 = "meio confuso";
int _if = "meio confuso";
int $ = "bem sucinto";
int $123 = "meio confuso";
int $if = "meio confuso";
// TODO posso usar $$ ou misturar $?
C#
int eu1;
var _ = "bem sucinto";
var _123 = "meio confuso";
var _if = "meio confuso";
// podemos ainda usar @ na frente
// do nome pra evitar colisões
// com palavras-chave e tipos
var @if = "muito confuso";
var @int = "muito confuso";
// TODO
// a diferença de @ ao invés de _
// é que...
Dart
TypeScript
JavaScript
let eu1;
let _ = "bem sucinto";
let _123 = "meio confuso";
let _if = "meio confuso";
// TODO misturar _
let $ = "bem sucinto";
let $123 = "meio confuso";
let $if = "meio confuso";
// TODO posso usar $$ ou misturar $?
// muitos frameworks utilizam $
// como nome de seus objetos
// principais
// jQuery deve ser o mais
// famoso
ActionScript
var eu1;
var _ = 'bem sucinto';
var _123 = 'meio confuso';
var _if = 'meio confuso';
var $ = 'bem sucinto';
var $$ = 'bem sucinto';
var $123 = 'meio confuso';
var $if = 'meio confuso';
var π = 3.14159;
var 你好 = "你好世界";
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Quem diria que um tópico tão simples seria tão diverso entre as linguagens?
Fortran usava =
e ALGOL usava :=
para atribuir valores às variáveis.
Nessa lista, apenas Ada, Object Pascal (Delphi) e Smalltalk utilizam o estilo ALGOL.
Como consequência, nestas linguagens como podemos ver, usamos =
para comparação, enquanto que as demais precisam usar algo como ==
.
Algumas linguagens como Lisp e SQL usam uma palavra-chave como set
para atribuição.
Rust e Swift são quase idênticos, mudando apenas uma coisa.
Swift faz a declaração de variáveis e constantes serem equivalentes
, enquanto Rust faz a declaração de variávies mais difíceis que de constantes. Mas porque Swift utilizou let
ao invés de const
?
JavaScript é a única das linguagens comparadas que possibilita mudar os tipos das variáveis dinamicamente. Sua sintaxe de desestruturação não permite declarar e atribuir um valor ao mesmo tempo. As variáveis já devem ser declaradas antes da atribuição. JavaScript possui um estilo legado de declaracão, que cria variáveis com regras de escopo diferentes do que a maioria dos programadores espera, além de possuir um modo estrito para coibir práticas legadas.
C++ é o que tem mais legado de coisas que não deram certo, e sua última sintaxe pode ter regras mais seguras, mas certamente é bastante estranha. Tipagem implícita requer a palavra auto
. Para aumentar a performance de nosso código, temos o recurso constexpr
.
Java parou no tempo e Objective-C também (mas cá entre nós, a Apple pelo menos admite). Porém, Objective-c ainda tem tipos ponteiro para deixar as coisas mais confusas. Python sequer tem constantes e o sistema de tipos é dinâmico.
Rust
// não existem tipos nullable
// mas existe um tipo std::Option<T>
// que pode conter None ou Some()
// tipo explícito
let mut k:Option<i32> = None;
let mut l:Option<AStruct> = None;
// tipo implícito Option<i32>
let mut m = None::<i32>;
let mut n = Some(10);
// erro, não pode passar um valor diretamente
// tem que usar Some(valor)
let mut o:Option<i32> = 10;
// não possui operador específico para Option
let p = match n { // p será do tipo i32
Some(some) => some,
None => 10,
};
// ok mas panic se for None
let q = n.unwrap(); // q será do tipo i32
Go
*k := nil
// nil para ponteiros
// e tipos que não são structs,
// array, slice, map, string, rune,
// boolean e números
C++
std::optional<int> k; // C++17
boost::optional<int> l; // boost
Objective-C
// nil object
// Nil class
// NSNull singleton to represent null
Swift
// optionals devem ter o tipo especificado
// em sua declaração
var k:Int? = nil
var l:AClass? = nil
let m = l?.propriedade // m recebe nil
let n = l!.propriedade // lança erro se l for nil
// nil coalescing operator
let o = k ?? 10 // o será do tipo Int
// ok mas não é idiomático
let p = k != nil ? k : 10 // p será do tipo Int?
// PS: nullable é chamado de optional
// e null é chamado de nil em Swift
Kotlin
// nullables devem ter o tipo especificado
// em sua declaração
var k:Int? = null
var l:AClass? = null
val m = l?.propriedade // m recebe null
val n = l!!.propriedade // lança erro se l for null
// null coalescing operator
val o = k ?: 10 // o será do tipo Int
Java
// tipos primitivos não podem ser nullable
int a = null; // erro
// qualquer tipo de referência é nullable
Integer k = null;
AClass l = null;
Integer m = (l != null) ? l.propriedade : null;
// Lombok possui a anotação
@NonNull
Integer k = 0;
// IntelliJ e Eclipse possuem uma anotação para auxiliar
// na checagem de nullables
@NotNull
Integer k = 0;
// não possui operador específico para null
int n = (k != null) ? k : 10; // n aceita ser do tipo int ou Integer
C#
// nullable não pode ser usado com var
// um tipo deve ser especificado
int? k = null;
AClass? l = null;
int? m = l?.propriedade; // C# 6
int? m = x?[indice]; // C# 6
int? m = (l != null) ? l.propriedade : null;
// null coalescing operator
var n = k ?? 10; // n será do tipo int
// ok mas não é idiomático
var o = (k != null) ? k : 10; // o será do tipo int?
Dart
// nullables devem ter o tipo especificado
// em sua declaração
int? k = null;
// TODO testar propriedades
TypeScript
// não existem tipos nullable
// mas é possível declarar um union
// que pode conter null e outros valores
type NullableNumber = number | undefined | null;
let k:NullableNumber = null;
let n = l!.propriedade(); // somente em tempo de compilação
JavaScript
'use strict';
// qualquer tipo é sempre nullable
let k = null;
let l = (k && k.propriedade) ? k.propriedade : null;
// null coalescing operator
let m = k || 10;
// ok mas não é idiomático
let n = (k || k === 0) ? k : 10;
ActionScript
// qualquer tipo é sempre nullable
var k = null;
var l = (k && k.propriedade) ? k.propriedade : null;
// null coalescing operator
var m = k || 10;
// ok mas não é idiomático
var n = (k || k === 0) ? k : 10;
Python
# qualquer tipo é sempre nullable
k = None
# mas podemos deixar explícito em funções com
from typing import Union, Optional
def foo(arg:Optional[int] = None) -> None:
def foo(arg:int | None) -> int | None:
PHP
// qualquer tipo é sempre nullable
$k = null;
VBA / VB6
Option Explicit
' qualquer tipo é sempre nullable
' mas o Visual Basic usa as palavras Empty e Nothing para tanto
' a palavra null é reservada para uso com bancos de dados
' Empty é o valor que uma variável não inicializada possui
Dim x: x = Empty
' Nothing só é usado com objetos TODO confirmar isso
Ada
-- somente tipos access (ponteiros
)
-- podem ter o valor null
type T_MyType_Access is access T_MyType;
-- TODO
Object Pascal (Delphi)
// ponteiros podem ter o valor nil
// TODO Varint pode também?
Ruby
# qualquer tipo é sempre nullable
k = nil
Smalltalk
"qualquer variável é sempre nullable"
|k|
k := nil
Common Lisp
nil
()
;; thereʼs also null, which contains nil…
Haskell
-- null em Haskell se chama bottom
-- como Haskell só tem constantes
-- uma constante com valor bottom
-- não seria muito útil
-- mas existe um tipo Maybe
-- que pode conter Nothing ou Just
f::Int -> Maybe Int
f 0 = Nothing
f x = Just x
g::Int -> Maybe Int
g 100 = Nothing
g x = Just x
h::Int -> Maybe Int
h x = case f x of
Just n -> g n
Nothing -> Nothing
h'::Int -> Maybe Int
h' x = do n <- f x
g n
-- Haskell possui o operador >>=
-- para extrair valores de Maybe
-- é o operador que está na logo
-- da linguagem
let monad = Maybe(x)
>>= f
>>= \n -> g(n)
F#
Web Assembly text format
(module
(memory $k 0)
(export "memory" (memory $k))
)
LLVM IR
; somente ponteiros
@k = global i8* null
Assembly
A
Rust
// tipo bool
let oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// parse
let toParse = "true";
let parsed:bool = toParse.parse().unwrap();
Go
// tipo bool
oitoOuOitenta := true
oitoOuOitenta = false
// converte para true
oitoOuOitenta = !oitoOuOitenta
// parse
toParse := "true"
parsed, err := strconv.ParseBool(toParse)
C++
// tipo bool
auto oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// TODO #include <boost/spirit/include/qi_bool.hpp>
Objective-C
// tipo NSNumber wrapping BOOL
NSNumber* oitoOuOitenta = @YES;
// tipo BOOL
BOOL oitoOuOitenta = YES;
// tipo C bool
bool oitoOuOitenta = true;
Swift
// tipo Bool
var oitoOuOitenta = true
oitoOuOitenta = false
// converte para true
oitoOuOitenta = !oitoOuOitenta
// lame...
let toParse = "true"
let parsed = toParse.lowercaseString == "true"
Kotlin
// tipo Boolean
var oitoOuOitenta = true
oitoOuOitenta = false
// converte para true
oitoOuOitenta = !oitoOuOitenta
// parse
var toParse = "true"
var parsed = toParse?.toBoolean()
Java
// tipo boolean
var oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// parse
var toParse = "true";
var parsed = Boolean.parseBoolean(toParse);
C#
// tipo bool
var oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// parse
var toParse = "true";
var parsed = Boolean.Parse(toParse);
// ou
var parsed = false;
var success = Boolean.TryParse(toParse, out parsed);
Dart
// tipo bool
var oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// lame...
var toParse = 'true';
var parsed = toParse.toLowerCase() == 'true';
TypeScript
// tipo Boolean
let oitoOuOitenta:boolean = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
JavaScript
// tipo Boolean
let oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// TODO falar de falsy e truthy e !!
/*
// falsy
var bZero = new Boolean(0);
var bNull = new Boolean(null);
var bEmptyString = new Boolean('');
var bfalse = new Boolean(false);
// undefined e NaN
// truthy
var btrueString = new Boolean('true');
var bfalseString = new Boolean('false');
var bSuLin = new Boolean('Su Lin');
var bArrayProto = new Boolean([]);
var bObjProto = new Boolean({});*/
ActionScript
// tipo Boolean
var oitoOuOitenta = true;
oitoOuOitenta = false;
// converte para true
oitoOuOitenta = !oitoOuOitenta;
// TODO falar de falsy e truthy e !!
// falsy
var bZero = new Boolean(0);
var bNull = new Boolean(null);
var bEmptyString = new Boolean('');
var bFalse = new Boolean(false);
var bNaN = new Boolean(NaN);
var bUndefined = new Boolean(undefined);
// truthy
var bTrueString = new Boolean('true');
var bFalseString = new Boolean('false');
var bSuLin = new Boolean('Su Lin');
var bArray = new Boolean([]);
var bObj = new Boolean({});
var bInfinity = new Boolean(Infinity);
var bNInfinity = new Boolean(-Infinity);
Python
# tipo Boolean
oitoOuOitenta = True
oitoOuOitenta = False
# converte para True
oitoOuOitenta = not oitoOuOitenta
# falsy
bZero = 0
bNone = None
bEmptyString = ''
bFalse = False
0.0
0j
Decimal(0)
Fraction(0, 1)
[] - an empty list
{} - an empty dict
() - an empty tuple
b'' - an empty bytes
set() - an empty set
an empty range, like range(0)
objects for which
obj.__bool__() returns False
obj.__len__() returns 0
PHP
VBA / VB6
Dim oitoOuOitenta: oitoOuOitenta = True
oitoOuOitenta = False
' converte para True
oitoOuOitenta = Not oitoOuOitenta
' parse
Dim toParse As String: toParse = "true"
Dim parsed As Boolean: parsed = CBool(toParse)
Ada
-- Usa enums: type Boolean is (False, True);
X:Boolean := True;
X := False;
-- converte para True
X := not X;
-- tricky due to letter casing
ToParse: constant String := "True";
Parsed:Boolean := Boolean'Value(ToParse);
Object Pascal (Delphi)
Ruby
oitoOuOitenta = true
oitoOuOitenta = false
# converte para true
oitoOuOitenta = !oitoOuOitenta
oitoOuOitenta = (not oitoOuOitenta)
# lame…
toParse = "true"
parsed = toParse.to_s.downcase == "true"
# falsy
# false
# nil
# truthy
# everything else
Smalltalk
Common Lisp
;; t is true and nil is false
(let((oitoOuOitenta t))
(setq oitoOuOitenta nil)
;; converte para t
(setq oitoOuOitenta (not oitoOuOitenta))
;; or (null) instead of (not)
;; lame…
(let(
(toParse "True")
parsed
)
(setq parsed (string-equal toParse "true"))
)
)
Haskell
F#
// idiomatic
// TODO
let IfThenElseExpression aBool =
let result = if aBool then 42 else 0
// note that the else case must be specified
printfn "result=%i" result
// statements + mutable
let mutable oitoOuOitenta = true
oitoOuOitenta <- false
// converte para true
oitoOuOitenta <- not false
// parse
// TODO
Web Assembly text format
LLVM IR
Assembly
A
Rust
tipo | tamanho |
---|---|
i8 | 8 bits |
i16 | 16 bits |
i32 | 32 bits |
i64 | 64 bits |
i128 | 128 bits (experimental) |
Go
tipo | tamanho |
---|---|
int8 | 8 bits |
int16 | 16 bits |
int32 | 32 bits |
int64 | 64 bits |
rune | 32 bits |
C++
tipo | tamanho |
---|---|
char | 8 bits? |
short | 16 bits ou mais |
int | 16 bits ou mais |
long | 32 bits ou mais |
long long | 64 bits ou mais |
tipo | tamanho |
---|---|
int8_t | 8 bits |
int16_t | 16 bits |
int32_t | 32 bits |
int64_t | 64 bits |
tipo | tamanho |
---|---|
int_least8_t | 8 bits ou mais |
int_least16_t | 16 bits ou mais |
int_least32_t | 32 bits ou mais |
int_least64_t | 64 bits ou mais |
tipo | tamanho |
---|---|
int_fast8_t | 8 bits ou mais |
int_fast16_t | 16 bits ou mais |
int_fast32_t | 32 bits ou mais |
int_fast64_t | 64 bits ou mais |
Objective-C
tipo | tamanho |
---|---|
char | 8 bits |
short | 16 bits |
int | 32 bits |
long | 32 ou 64 bits |
long long | 64 bits |
tipo | tamanho |
---|---|
int8_t | 8 bits |
int16_t | 16 bits |
int32_t | 32 bits |
int64_t | 64 bits |
tipo | tamanho |
---|---|
int_least8_t | 8 bits ou mais |
int_least16_t | 16 bits ou mais |
int_least32_t | 32 bits ou mais |
int_least64_t | 64 bits ou mais |
Swift (Obj-C)
tipo | tamanho |
---|---|
CChar | 8 bits |
CShort | 16 bits |
CInt | 16 bits |
CLong | 32 bits |
CLongLong | 64 bits |
Swift
tipo | tamanho |
---|---|
Int8 | 8 bits |
Int16 | 16 bits |
Int32 | 32 bits |
Int64 | 64 bits |
Kotlin
tipo | tamanho |
---|---|
Byte | 8 bits |
Short | 16 bits |
Int | 32 bits |
Long | 64 bits |
Java
tipo | tamanho |
---|---|
byte | 8 bits |
short | 16 bits |
int | 32 bits |
long | 64 bits |
C#
tipo | tamanho |
---|---|
sbyte | 8 bits |
short | 16 bits |
int | 32 bits |
long | 64 bits |
decimal | 128 bits |
Dart
tipo | tamanho |
---|---|
int | 64 bits |
TypeScript
JavaScript
-ActionScript
tipo | tamanho |
---|---|
int | 32 bits |
Number | 64 bits |
Python
-PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
tipo | tamanho |
---|---|
iN | N bits |
i1 | 1 bit |
i8388607 | 8388607 bits |
Assembly
Rust
tipo | tamanho |
---|---|
u8 | 8 bits |
u16 | 16 bits |
u32 | 32 bits |
u64 | 64 bits |
u128 | 128 bits (experimental) |
Go
tipo | tamanho |
---|---|
uint8 | 8 bits |
uint16 | 16 bits |
uint32 | 32 bits |
uint64 | 64 bits |
byte | 8 bits |
C++
tipo | tamanho |
---|---|
char | 8 bits? |
unsigned short | 16 bits ou mais |
unsigned int | 16 bits ou mais |
unsigned long | 32 bits ou mais |
unsigned long long | 64 bits ou mais |
tipo | tamanho |
---|---|
uint8_t | 8 bits |
uint16_t | 16 bits |
uint32_t | 32 bits |
uint64_t | 64 bits |
tipo | tamanho |
---|---|
uint_least8_t | 8 bits ou mais |
uint_least16_t | 16 bits ou mais |
uint_least32_t | 32 bits ou mais |
uint_least64_t | 64 bits ou mais |
tipo | tamanho |
---|---|
uint_fast8_t | 8 bits ou mais |
uint_fast16_t | 16 bits ou mais |
uint_fast32_t | 32 bits ou mais |
uint_fast64_t | 64 bits ou mais |
Objective-C
tipo | tamanho |
---|---|
unsigned char | 8 bits |
unsigned short | 16 bits |
unsigned int | 32 bits |
unsigned long | 32 ou 64 bits |
unsigned long long | 64 bits |
tipo | tamanho |
---|---|
uint8_t | 8 bits |
uint16_t | 16 bits |
uint32_t | 32 bits |
uint64_t | 64 bits |
tipo | tamanho |
---|---|
uint_least8_t | 8 bits ou mais |
uint_least16_t | 16 bits ou mais |
uint_least32_t | 32 bits ou mais |
uint_least64_t | 64 bits ou mais |
Swift (Obj-C)
tipo | tamanho |
---|---|
CUnsignedChar | 8 bits |
CUnsignedShort | 16 bits |
CUnsignedInt | 16 bits |
CUnsignedLong | 32 bits |
CUnsignedLongLong | 64 bits |
Swift
tipo | tamanho |
---|---|
UInt8 | 8 bits |
UInt16 | 16 bits |
UInt32 | 32 bits |
UInt64 | 64 bits |
Kotlin
-Java
-C#
tipo | tamanho |
---|---|
byte | 8 bits |
ushort | 16 bits |
uint | 32 bits |
ulong | 64 bits |
Dart
-TypeScript
JavaScript
-ActionScript
tipo | tamanho |
---|---|
uint | 32 bits |
Number | 64 bits |
Python
-PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
tipo | tamanho |
---|---|
isize | Depende do hardware |
usize | Depende do hardware |
Go
tipo | tamanho |
---|---|
int | Depende do hardware |
uint | Depende do hardware |
uintptr | Depende do hardware |
C++
tipo | tamanho |
---|---|
intptr_t | Depende do hardware |
uintptr_t | Depende do hardware |
Objective-C
tipo | tamanho |
---|---|
NSInteger | 32 ou 64 bits |
NSUInteger | 32 ou 64 bits |
Swift (Obj-C)
-Swift
tipo | tamanho |
---|---|
Int | Depende do Hardware |
UInt | Depende do Hardware |
Kotlin
-Java
-C#
tipo | tamanho |
---|---|
nint | Depende do Hardware |
nuint | Depende do Hardware |
Dart
-TypeScript
JavaScript
-ActionScript
-Python
tipo | tamanho |
---|---|
Integer | Depende do Hardware |
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
tipo | tamanho |
---|---|
f32 | 32 bits |
f64 | 64 bits |
Go
tipo | tamanho |
---|---|
float32 | 32 bits |
float64 | 64 bits |
C++
tipo | tamanho |
---|---|
float | 32 bits |
double | 64 bits |
tipo | tamanho |
---|---|
long double | 128 bits |
Objective-C
tipo | tamanho |
---|---|
float | 32 bits |
double | 64 bits |
tipo | tamanho |
---|---|
long double | 128 bits |
Swift (Obj-C)
tipo | tamanho |
---|---|
CFloat | 32 bits |
CDouble | 64 bits |
Swift
tipo | tamanho |
---|---|
Float | 32 bits |
Double | 64 bits |
Kotlin
tipo | tamanho |
---|---|
float | 32 bits |
double | 64 bits |
Java
tipo | tamanho |
---|---|
float | 32 bits |
double | 64 bits |
C#
tipo | tamanho |
---|---|
float | 32 bits |
double | 64 bits |
tipo | tamanho |
---|---|
decimal | 128 bits |
Dart
tipo | tamanho |
---|---|
double | 64 bits |
TypeScript
JavaScript
tipo | tamanho |
---|---|
Number | 64 bits |
ActionScript
tipo | tamanho |
---|---|
Number | 64 bits |
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
tipo | tamanho |
---|---|
half | 16 bits |
float | 32 bits |
double | 64 bits |
fp128 | 128 bits |
tipo | tamanho |
---|---|
bfloat | 16 bits |
x86_fp80 | 80 bits |
ppc_fp128 | 128 bits |
Assembly
Rust
-Go
tipo | tamanho |
---|---|
complex64 | 64 bits |
complex128 | 128 bits |
C++
-Objective-C
-Swift (Obj-C)
-Swift
-Kotlin
-Java
-C#
-Dart
-TypeScript
JavaScript
-ActionScript
-Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
-Assembly
Rust
tipo | tamanho |
---|---|
num::bigint::BigInt | ? |
num::bigint::BigUint | ? |
Go
C++
-Objective-C
tipo | tamanho |
---|---|
NSNumber | cluster de tipos |
CGFloat | 32 ou 64 bits |
Swift (Obj-C)
-Swift
tipo | tamanho |
---|---|
Float80 | 80 bits |
Kotlin
tipo | tamanho |
---|---|
java.math.BigInteger | ? |
java.math.BigDecimal | ? |
Java
tipo | tamanho |
---|---|
BigInteger | ? |
BigDecimal | ? |
C#
tipo | tamanho |
---|---|
BigInteger | ? |
Complex | ? |
Dart
TypeScript
JavaScript
tipo | tamanho |
---|---|
BigInt | ? |
ActionScript
-Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
-Assembly
Rust nomeia claramente os tipos numéricos que usa, além de usar nomes curtos.
Swift prefere ser um pouco mais conservador e utilizar nomes como Int
e Double
. Possui também tipos para compatibilidade com as APIs em C e Objective-C.
C# mantém os nomes herdados do C (embora seja possível criar type aliases por arquivo). Notem a inconsistência com sbyte
e byte
devido a esta decisão. C# possui um tipo de 128 bits. Como roda numa máquina virtual, não possui tipos com tamanhos de memória como Rust e Swift. Não sei ao certo como é feito com Native .NET.
Java não possui tipos sem sinal.
C++ possui uma leve melhoria em relação à C, mas ainda é bem extenso.
Objective-C mistura tipos de C e os próprios, fazendo uma salada só. Os tipos que ele herda de C não possuem tamanho fixo. Existe apenas a garantia de que short <= int <= long <= long long
. Mesma coisa vale para float <= double <= long double
. Então existem tipos de tamanho fixo criados na especificação C99 e os tipos incluídos pelo framework da Apple.
JavaScript só possui um tipo numérico.
Notem que existe uma divergência entre C++ e Objective-C e as demais linguagens em relação à nomeclatura. Para as duas linguagens, int
e long
possuem tamanhos diferentes das demais. Por isso, ponto para as linguagens que indicam explicitamente o tamanho dos tipos no próprio nome.
Rust
-Go
C++
-Objective-C
tipo | classe |
---|---|
? | NSNumber |
Swift
-Kotlin
tipo | classe |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
tipo | classe |
---|---|
float | Float |
double | Double |
Java
tipo | classe |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
tipo | classe |
---|---|
float | Float |
double | Double |
C#
tipo | struct |
---|---|
sbyte | SByte |
short | Int16 |
int | Int32 |
long | Int64 |
decimal | Decimal |
tipo | classe |
---|---|
byte | Byte |
ushort | UInt16 |
uint | UInt32 |
ulong | UInt64 |
tipo | classe |
---|---|
float | Single |
double | Double |
tipo | classe |
---|---|
decimal | Decimal |
Dart
TypeScript
JavaScript
-ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
-Assembly
A
Rust
// i8
let i81 = 1_i8;
let i82 = -1i8;
// u8
let u81 = 1_u8;
// i16
let i161 = 1i16;
let i162 = -1_i16;
// u16
let u161 = 1u16;
// i32
let i1 = 1;
let i2 = -1;
let i3 = 1_i32;
// avisa overflow -2147483648
let i4:i32 = 2_147_483_648;
let i5 = 2_147_483_648_i32;
let i6 = 2_147_483_648;
// avisa underflow 2147483647
let i7:i32 = -2_147_483_649;
let i8 = -2_147_483_649_i32;
let i9 = -2_147_483_649;
// u32
let u1 = 2_147_483_648_u32;
// i64
let i641 = 1_i64;
let i642 = -1_i64;
// u64
let u641 = 1_u64;
// pointer size
let isize1 = 1_isize;
let usize1 = 1_usize;
Go
// pointer size
i1 := 1
i2 := 2_147_483_648 // se x64 ok
i3 := -2_147_483_649 // se x64 ok
// lança exceção
// contant ix overflows int32
var i4 int32 = 2_147_483_648
var i5 int32 = -2_147_483_649
// lança exceção
// contant e1 overflows int
e1 := 9_223_372_036_854_775_808
C++
// int32_t (x64 LP64)
auto i1{1};
auto i2{-1};
// uint32_t (x64 LP64)
auto u1{1u};
auto u2{2'147'483'648U};
// int64_t (x64 LP64)
auto l1{2'147'483'648};
auto l2{-2'147'483'649};
auto l3{1l};
auto l4{1L};
auto l5{1ll};
auto l6{1LL};
// uint64_t (x64 LP64)
auto ul1{9'223'372'036'854'775'808};
auto ul2{1ul};
auto ul3{1UL};
auto ul4{1ull};
auto ul5{1ULL};
Objective-C
// TODO
NSNumber* myBool = @YES;
NSNumber* myBool = [[NSNumber alloc] initWithBOOL:YES];
// int
NSInteger i1 = 42; // NSLog(@"%zd", i1);
NSNumber* i2 = @42; // NSLog(@"%@", i2);
NSNumber* i3 = [[NSNumber alloc] initWithInt:42];
// uint
NSUInteger u1 = 42u; // NSLog(@"%tu", u1);
NSNumber* u2 = @42u; // NSLog(@"%@", u2);
NSNumber* u3 = [[NSNumber alloc] initWithUnsignedInt:42u];
// long
NSNumber* l1 = @42L;
NSNumber* l1 = [[NSNumber alloc] initWithLong:42L];
// long long
NSNumber* ll1 = @42LL;
NSNumber* ll1 = [[NSNumber alloc] initWithLong:42LL];
Swift
// Int (x64)
let i1 = 1
let i2 = -1
let i3 = 2_147_483_648
let i4 = -2_147_483_649
// UInt (x64)
let u1:UInt = 9_223_372_036_854_775_808
// lança exceção
// does not fit inside Int (x64)
let e1 = 9_223_372_036_854_775_808
Kotlin
// Int
val i1 = 1
val 12 = -1
val i3 = 2_147_483_648
val i4 = -2_147_483_649
// Long
val l1 = 1L
Java
// int
Object i1 = 1;
Object i2 = -1;
// long
Object l1 = 2_147_483_648l;
Object l2 = -2_147_483_649L;
Object l3 = 1l;
Object l4 = 1L;
// lança exceção
// integer number too large
Object l5 = 9_223_372_036_854_775_808L;
C#
// int
var i1 = 1;
var i2 = -1;
// uint
var u1 = 1u;
var u2 = 2147483648U;
var u3 = 2147483648;
// long
var l1 = 2147483648L;
var l2 = -2147483649;
var l3 = -2147483649L;
var l4 = 1l;
var l5 = 1L;
// ulong
// terminal com ul ou lu
// TODO
Dart
// TODO
// int
var i1 = 1;
var i2 = -1;
var i3 = 2147483648;
var i4 = -2147483649;
var u1 = 9223372036854775808;
// lança exceção?
// ?
var e1 = 9223372036854775808;
TypeScript
JavaScript
let i1 = 1n;
ActionScript
var i1 = 1; // Number
var i2:int = 2147483648; // overflows
var i3 = 2147483648; // Number
// avisa underflow 2147483647
var i4:int = -2147483649; // underflows
var i5 = -2147483649; // Number
// u32
var u1:uint = 2147483648;
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
// f32 (float)
let f1 = 1f32;
// f64 (double)
let d1 = 1f64;
let d2 = 1.0;
Go
// float32
f1 := float32(1)
// float64
d1 := 1.0
d2 := .7
C++
Objective-C
// NSNumber wrapping float
NSNumber* f1 = @1f;
NSNumber* f1m = [NSNumber numberWithFloat:1f];
// NSNumber wrapping double
NSNumber *d1 = @1.0;
NSNumber *d1m = [NSNumber numberWithDouble:1.0];
Swift
// Float
let f1:Float = 1
// Double
let d1 = 1.0
let d2 = 0.7 // não aceita .7
Kotlin
// Float
val f1 = 1f
val f2 = 1F
// Double
val d1 = 1.0
val d2 = .7
Java
// float
Object f1 = 1f;
Object f2 = 1F;
// double
Object d1 = 1d;
Object d2 = 1D;
Object d3 = 1.0;
Object d4 = .7;
C#
// float
var f1 = 1f;
var f2 = 1F;
// double
var db1 = 1d;
var db2 = 1D;
var db3 = 1.0;
var db4 = .7;
// decimal
var dc = 1m;
Dart
TypeScript
JavaScript
// double
let d1 = 1;
let d2 = -1;
let d3 = 2147483648;
let d4 = -2147483649;
let d5 = 1.0;
let d6 = .7;
ActionScript
// double
var d1 = 1;
var d2 = -1;
var d3 = 2147483648;
var d4 = -2147483649;
var d5 = 1.0;
var d6 = .7;
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
// notação científica
let c1 = 1e_0;
let c2 = 1e-1;
let c3 = -0.7_e-2;
// notação binária
let b1 = 0b_0000_0001;
let b2 = -0b0000_0010;
// notação octal
let o1 = 0o_01234567;
let o2 = -0o1234567;
// notação hexadecimal
let cor = 0x_ff_00_00;
let x1 = -0x0123456789ABCDEF;
// TODO misturar notações
// com sufixos
Go
// notação científica
c1 := 1e0
c2 := 1e-1
c3 := -.7e-2
// notação binária
b1 := 0b_0000_0001
b2 := -0B0000_0010
// notação octal
o1 := 0o_01234567
o2 := -0O1234567
// notação hexadecimal
cor := 0x_ff_00_00
x1 := -0X0123456789ABCDEF
// notação hexadecimal científica
xc1 := 0x1p-2 // == 0.25
xc2 := 0x2.p10 // == 2048.0
xc3 := 0x1.Fp+0 // == 1.9375
C++
Objective-C
Swift
// notação científica
let c1 = 1e0
let c2 = 1e-1
let c3 = -0.7_e-2
// notação binária
let b1 = 0b0000_0001
let b2 = -0b0000_0010
// notação octal
let o1 = 0o01234567
let o2 = -0o1234567
// notação hexadecimal
let cor = 0xff_00_00
let x1 = -0x0123456789ABCDEF
// notação hexadecimal científica
let xc1 = 0xff0000p0
let xc2 = -0x0123456789ABCDEF_p9
Kotlin
// notação científica
val c1 = 1e0
val c2 = 1e-1
val c3 = -.7e-2
// notação binária
val b1 = 0b0000_0001
val b2 = -0B0000_0010
// notação hexadecimal
val cor = 0xff_00_00
val x1 = -0X0123456789ABCDEF
Java
// notação científica
double c1 = 1e0;
double c2 = 1e-1;
double c3 = -.7e-2;
// notação binária
int b1 = 0b0000_0001;
int b2 = -0B00000010;
// notação octal
int o1 = 01_234_567;
int o2 = -01234567;
// notação hexadecimal
int cor = 0xff_00_00;
int x1 = -0X0123456789ABCDEF;
// TODO misturar notações
// com sufixos
C#
// notação científica
double c1 = 1e0;
double c2 = 1e-1;
double c3 = -.7e-2;
// notação binária - C# 7+
val b1 = 0b0000_0001
val b2 = -0B0000_0010
// notação hexadecimal
int cor = 0xff0000;
int x1 = -0X0123456789ABCDEF;
// TODO misturar notações
// com sufixos
Dart
TypeScript
JavaScript
// notação científica
let c1 = 1e0;
let c2 = 1e-1;
let c3 = -.7e-2;
// notação binária
let b1 = 0B0000_0001;
let b2 = -0b0000_0010;
// notação octal
let o1 = 0o0123_4567;
let o2 = -0O123_4567;
// notação hexadecimal
let cor = 0xff_00_00;
let x1 = -0X0123456789ABCDEF;
// separadores _ requerem
// Chrome 75+
// Firefox 70+
// Safari 13+
ActionScript
// notação científica
var c1 = 1e0;
var c2 = 1e-1;
var c3 = -.7e-2;
// ignora leading zeroes
var i1 = 01234567;
var i2 = -01234567;
// notação hexadecimal
var cor = 0xff0000;
var x1 = -0X0123456789ABCDEF;
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
let i1 = 10;
let p1 = 01;
let p2 = 00.1;
Go
i1 := 10
// desde go 1.13, antes era
// considerado octal
p1 := 01
p2 := 00.1
C++
// números começando com 0
// são considerados notação
// octal
Objective-C
Swift
let i1 = 10
let p1 = 01
let p2 = 00.1
Kotlin
val p2 = 00.1
Java
// números começando com 0
// são considerados notação
// octal
C#
var i1 = 10;
var p1 = 01;
var p2 = 00.1;
Dart
TypeScript
JavaScript
let i1 = 10;
let p1 = 01;
ActionScript
var i1 = 10;
var p1 = 01;
var p2 = 00.1;
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
A
Rust
// Requer compilação com flag -O
// Compilações sem otimização panic no overflow
let i32_1:i32 = 2;
let i32_2:i32 = 4;
let i32_min:i32 = std::i32::MIN;
let i32_max:i32 = std::i32::MAX;
let i64_1:i64 = i32_max as i64; // explicit conversion 2147483647 (i64)
let i16_1:i16 = i32_max as i16; // explicit conversion -1 (i16)
// explicit conversion
let adicao1 = i32_max + 1; // -2147483648 (i32)
let adicao2 = i64_1 + (i32_1 as i64); // 2147483649 (i64)
let adicao3 = i64_1 + (i32_max as i64); // 4294967294 (i64)
// explicit conversion
let subtracao1 = i32_min - 1; // 2147483647 (i32)
let subtracao2 = (i16_1 as i32) - i32_1; // -3 (i32)
let subtracao3 = (i16_1 as i32) - i32_max; // -2147483648 (i32)
// explicit conversion
let multiplicacao1 = i32_1 * i32_2; // 8 (i32)
let multiplicacao2 = i32_max * i32_1; // -2 (i32)
let multiplicacao3 = (i32_1 as i64) * i64_1; // 4294967294 (i64)
// explicit conversion
let divisao1 = i32_2 / i32_1; // 2 (i32)
let divisao2 = i32_1 / i32_2; // 0 (i32)
let divisao3 = (i16_1 as i32) / i32_1; // 0 (i32)
// NOTA
// literais numéricas sem sufixo possuem o tipo _
// e não realizam operações matemáticas
// TODO converte para char e boolean
Go
// requer import "math"
// integer literals without type are int by default, not int32
var i32_1 int32 = 2
var i32_2 int32 = 4
var i32_min int32 = math.MinInt32
var i32_max int32 = math.MaxInt32
i64 := int64(i32_max) // explicit conversion 2147483647 (int64)
i16 := int16(i32_max) // explicit conversion -1 (int16)
// implicit conversion
adicao1 := i32_max + 1 // 2147483648 (int64)
subtracao1 := i32_min - 1 // -2147483649 (int64)
// explicit conversion
adicao2 := i64 + int64(i32_1) // 2147483649 (int64)
adicao3 := i64 + int64(i32_max) // 4294967294 (int64)
subtracao2 := int32(i16) - i32_1 // -3 (int32)
subtracao3 := int32(i16) - i32_max // -2147483648 (int32)
// explicit conversion
multiplicacao1 := i32_1 * i32_2 // 8 (int32)
multiplicacao2 := i32_max * i32_1 // -2 (int32)
multiplicacao3 := int64(i32_1) * i64 // 4294967294 (int64)
// explicit conversion
divisao1 := i32_2 / i32_1 // 2 (int32)
divisao2 := i32_1 / i32_2 // 0 (int32)
divisao3 := int32(i16) / i32_1 // 0 (int32)
intVar := 1
doubleVar := 0.1
// requer conversão explícita
somaVar := float64(intVar) + doubleVar
doubleVar += float64(intVar)
// não requer
somaLiteral := 1 + 0.1
doubleVar += 1
C++
Objective-C
Swift
// Conversão explícita é sempre requerida para
// operações com variáveis
let i32_1:Int32 = 2
let i32_2:Int32 = 4
let i32_min:Int32 = Int32.min
let i32_max:Int32 = Int32.max
let i64:Int64 = Int64(i32_max) // explicit conversion 2147483647 (Int64)
let i16:Int16 = Int16(truncatingBitPattern: i32_max) // explicit conversion -1 (Int16)
// explicit conversion and overflow operator &+
var adicao1 = i32_max &+ 1 // -2147483648 (Int32)
var adicao2 = i64 + Int64(i32_1) // 2147483649 (Int64)
var adicao3 = i64 + Int64(i32_max) // 4294967294 (Int64)
// explicit conversion and overflow operator &-
var subtracao1 = i32_min &- 1 // 2147483647 (Int32)
var subtracao2 = Int32(i16) &- i32_1 // -3 (Int32)
var subtracao3 = Int32(i16) &- i32_max // -2147483648 (Int32)
// explicit conversion and overflow operator &*
var multiplicacao1 = i32_1 * i32_2 // 8 (Int32)
var multiplicacao2 = i32_max &* i32_1 // -2 (Int32)
var multiplicacao3 = Int64(i32_1) * i64 // 4294967294 (Int64)
// explicit conversion
var divisao1 = i32_2 / i32_1 // 2 (Int32)
var divisao2 = i32_1 / i32_2 // 0 (Int32)
var divisao3 = Int32(i16) / i32_1 // 0 (Int32)
// NOTA
// Literais numéricas não possuem tipo específico,
// apenas variáveis possuem. Portanto realizar
// operações com variáveis requer conversões
// explícitas, enquanto que operações com literais
// não requer
let intVar = 1
var doubleVar = 0.1
// requer conversão explícita
let somaVar = Double(intVar) + doubleVar
doubleVar += Double(intVar)
// não requer
let somaLiteral = 1 + 0.1
doubleVar += 1
Kotlin
Java
int i32_1 = 2;
int i32_2 = 4;
int i32_min = Integer.MIN_VALUE;
int i32_max = Integer.MAX_VALUE;
long i64 = i32_max; // implicit conversion 2147483647 (long)
short i16 = (short)i32_max; // explicit conversion -1 (short)
// usa o tipo maior
Object adicao1 = i32_max + 1; // -2147483648 (int)
Object adicao2 = i64 + i32_1; // 2147483649 (long)
Object adicao3 = i64 + i32_max; // 4294967294 (long)
// usa o tipo maior
Object subtracao1 = i32_min - 1; // 2147483647 (int)
Object subtracao2 = i16 - i32_1; // -3 (int)
Object subtracao3 = i16 - i32_max; // -2147483648 (int)
// usa o tipo maior
Object multiplicacao1 = i32_1 * i32_2; // 8 (int)
Object multiplicacao2 = i32_max * i32_1; // -2 (int)
Object multiplicacao3 = i32_1 * i64; // 4294967294 (long)
// usa o tipo maior
Object divisao1 = i32_2 / i32_1; // 2 (int)
Object divisao2 = i32_1 / i32_2; // 0 (int)
Object divisao3 = i16 / i32_1; // 0 (int)
// TODO char converte tb
C#
unchecked {
int i32_1 = 2;
int i32_2 = 4;
int i32_min = Int32.MinValue;
int i32_max = Int32.MaxValue;
long i64 = i32_max; // implicit conversion 2147483647 (long)
short i16 = (short)i32_max; // explicit conversion -1 (short)
// usa o tipo maior
var adicao1 = i32_max + 1; // -2147483648 (int)
var adicao2 = i64 + i32_1; // 2147483649 (long)
var adicao3 = i64 + i32_max; // 4294967294 (long)
// usa o tipo maior
var subtracao1 = i32_min - 1; // 2147483647 (int)
var subtracao2 = i16 - i32_1; // -3 (int)
var subtracao3 = i16 - i32_max; // -2147483648 (int)
// usa o tipo maior
var multiplicacao1 = i32_1 * i32_2; // 8 (int)
var multiplicacao2 = i32_max * i32_1; // -2 (int)
var multiplicacao3 = i32_1 * i64; // 4294967294 (long)
// usa o tipo maior
var divisao1 = i32_2 / i32_1; // 2 (int)
var divisao2 = i32_1 / i32_2; // 0 (int)
var divisao3 = i16 / i32_1; // 0 (int)
}
// conversão implícita se o número couber no outro
// byte -> int, uint ou float por exemplo
// sbyte -> int ou float
// conversão explícita
// entre integrals
// entre floats
// de floats para integrals
// tipo numerico não converte pra char
/*
When you convert from a double or float value to an integral type,
the value is truncated. If the resulting integral value is outside
the range of the destination value, the result depends on the
overflow checking context.
When you convert double to float, the double value is rounded
to the nearest float value. If the double value is too small
or too large to fit into the destination type, the result
will be zero or infinity.
When you convert decimal to float or double, the decimal value is rounded
to the nearest double or float value.
*/
Dart
TypeScript
JavaScript
'use strict';
// só usa um único tipo numérico double
// não há o que converter
// números não sofrem overflow nem underflow,
// e não dão aviso se você tentar passar
// dos limites
let i = Number.MAX_VALUE;
let j = Number.MAX_VALUE + 1; // não dá aviso
if (i === j) {
console.log('j foi limitado');
}
i = -i
j = -j - 1; // não dá aviso
if (i === j) {
console.log('j foi limitado');
}
ActionScript
var i32_1:int = 2;
var i32_2:int = 4;
var i32_min:int = int.MIN_VALUE;
var i32_max:int = int.MAX_VALUE;
var n_max:int = Number.MAX_VALUE;
var i64_1:Number = i32_max as Number; // explicit conversion 2147483647 (Number)
var i32cast_1:int = (n_max as int); // explicit conversion 0 (int)
// explicit conversion
var adicao1 = i32_max + 1; // 2147483648 (Number)
var adicao2 = i64_1 + (i32_1 as Number); // 2147483649 (Number)
var adicao3 = i64_1 + (i32_max as Number); // 4294967294 (Number)
// explicit conversion
var subtracao1 = i32_min - 1; // -2147483649 (Number)
var subtracao2 = (i32cast_1 as Number) - i32_1; // -2 (Number)
var subtracao3 = (i32cast_1 as Number) - i32_max; // -2147483647 (Number)
// explicit conversion
var multiplicacao1 = i32_1 * i32_2; // 8 (int)
var multiplicacao2 = i32_max * i32_1; // 4294967294 (Number)
var multiplicacao3 = (i32_1 as Number) * i64_1; // 4294967294 (Number)
// explicit conversion
var divisao1 = i32_2 / i32_1; // 2 (int)
var divisao2 = i32_1 / i32_2; // 0.5 (Number)
var divisao3 = (i32cast_1 as Number) / i32_1; // 0 (Number)
var divisao4 = (i32_2 as Number) / i32_1; // 2 (Number)
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
/*
{
// conversão explícita de int para byte 1
this.recebeByte((byte)1);
// conversão explícita 44
this.recebeByte((byte)300);
}
private void recebeByte(byte numero) {
System.out.println("\nRecebe byte");
System.out.println(numero);
}
*/
C#
Dart
TypeScript
JavaScript
// só usa um único tipo numérico double
// não há o que converter
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
let i = s.parse::<i32>().unwrap();
let i:i32 = s.parse().unwrap();
let i:i32 = s.parse::<i32>().unwrap_or(0);
let i = match s.parse::<i32>() {
Ok(i) => i,
Err(_e) => 0,
};
Go
// requer import "strconv"
// "a to i" e "i to a" string <--> int base 10
i, err := strconv.Atoi("-42")
s := strconv.Itoa(-42)
f, err := strconv.ParseFloat("3.1415", 64) // size 64
i, err := strconv.ParseInt("-42", 10, 64) // base 10 size 64
u, err := strconv.ParseUint("42", 10, 64) // base 10 size 64
C++
auto i = std::stoi(s); // #include <string>
int i;
i = std::from_chars(s.data(), s.data() + s.size(), i, 10);
Objective-C
int i = [s intValue];
s.intValue;
[@" 2 some non-digit characters" intValue]; // 2
Swift
let i = Int(s) ?? 0
Kotlin
val i = s.toInt()
Java
var i = Integer.parseInt(s);
var i = new Integer(s).intValue();
C#
var i = int.Parse(s);
var i = Convert.ToInt64(s);
Dart
TypeScript
JavaScript
parseInt('1111', 2); // base 2
parseInt(15.99, 10);
parseInt('15,123', 10);
parseInt('15 * 3', 10);
parseInt('15e2', 10);
parseInt('FXX123', 16);
// dangerous, no base specified
// chooses base depending on string format
parseFloat('3.14');
parseFloat('314e-2');
parseFloat('0.0314E+2');
parseInt('015', 10); // but `parseInt(015, 8)` will return 13
parseFloat('3.14some non-digit characters');
ActionScript
parseInt('1111', 2); // 15
parseInt('15,123', 10); // 15
parseInt('15 * 3', 10); // 15
parseInt('15e2', 10); // 15
parseInt('FXX123', 16); // 15
parseInt('FXX123', 10); // NaN
// dangerous, no base specified
// chooses base depending on string format
parseInt('FXX123'); // 15
parseFloat('3.14'); // 3.14
parseFloat('314e-2'); // 3.14
parseFloat('0.0314E+2'); // 3.14
parseInt('015', 10); // 15
parseInt('015', 8); // 13
parseFloat('3.14some non-digit characters'); // 3.14
Python
i = int(s)
PHP
VBA / VB6
Dim i As Integer = CInt((s))
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
A
Check https://gmpreussner.com/research/dimensional-analysis-in-programming-languages for a much more in depth coverage of this topic.
Rust
// check macros
// https://stackoverflow.com/questions/60790226/custom-literals-via-rust-macros
// check libraries
// https://github.com/iliekturtles/uom
// https://github.com/paholg/dimensioned
//
Go
-C++
// uses boost
struct length_base_dimension : base_dimension<length_base_dimension, 1> { };
struct mass_base_dimension : base_dimension<mass_base_dimension, 2> { };
struct time_base_dimension : base_dimension<time_base_dimension, 3> { };
typedef length_base_dimension::dimension_type length_dimension;
typedef mass_base_dimension::dimension_type mass_dimension;
typedef time_base_dimension::dimension_type time_dimension;
typedef derived_dimension<length_base_dimension, 2>::type area_dimension;
typedef derived_dimension<mass_base_dimension, 1,
length_base_dimension, 2,
time_base_dimension, -2>::type energy_dimension;
struct meter_base_unit : base_unit<meter_base_unit, length_dimension, 1> { };
struct kilogram_base_unit : base_unit<kilogram_base_unit, mass_dimension, 2> { };
struct second_base_unit : base_unit<second_base_unit, time_dimension, 3> { };
typedef make_system<
meter_base_unit,
kilogram_base_unit,
second_base_unit>::type mks_system;
typedef unit<dimensionless_type, mks_system> dimensionless;
typedef unit<length_dimension, mks_system> length;
typedef unit<mass_dimension, mks_system> mass;
typedef unit<time_dimension, mks_system> time;
BOOST_UNITS_STATIC_CONSTANT(meter, length);
BOOST_UNITS_STATIC_CONSTANT(meters, length);
BOOST_UNITS_STATIC_CONSTANT(kilogram, mass);
BOOST_UNITS_STATIC_CONSTANT(kilograms, mass);
BOOST_UNITS_STATIC_CONSTANT(second, time);
BOOST_UNITS_STATIC_CONSTANT(seconds, time);
template<> struct base_unit_info<test::meter_base_unit> {
static std::string name() { return "meter"; }
static std::string symbol() { return "m"; }
};
template<> struct base_unit_info<test::kilogram_base_unit>
{
static std::string name() { return "kilogram"; }
static std::string symbol() { return "kg"; }
};
template<> struct base_unit_info<test::second_base_unit>
{
static std::string name() { return "second"; }
static std::string symbol() { return "s"; }
};
Unit systems defined in this way may then be used as follows:
quantity<length> L(2.0 * meters);
quantity<energy> E = kilograms * pow<2>(L / seconds);
quantity<length, std::complex<double> > L(std::complex<double>(3.0, 4.0) * meters);
quantity<energy, std::complex<double> > E(kilograms * pow<2>(L / seconds));
const double dimless = (L/L);
Objective-C
-Swift
-Kotlin
-Java
// check JSR 363
import javax.measure;
C#
-Dart
-TypeScript
-JavaScript
-ActionScript
-Python
-PHP
-VBA / VB6
-Ada
-- https://www.adacore.com/gems/gem-136-how-tall-is-a-kilogram
type Mks_Type is new Long_Long_Float
with
Dimension_System => (
(Unit_Name => Meter, Unit_Symbol => 'm', Dim_Symbol => 'L'),
(Unit_Name => Second, Unit_Symbol => 's', Dim_Symbol => 'T'),
...
subtype Length is Mks_Type
with
Dimension => (Symbol => 'm',
Meter => 1,
others => 0);
subtype Time is Mks_Type
with
Dimension => (Symbol => 's',
Second => 1,
others => 0);
m : constant Length := 1.0;
s : constant Time := 1.0;
cm : constant Length := 1.0E-02;
km : constant Length := 1.0E+03;
min : constant Time := 60.0 * s;
hour : constant Time := 60.0 * min;
subtype Area is Mks_Type
with
Dimension => (
Meter => 2,
others => 0);
subtype Speed is Mks_Type
with
Dimension => (
Meter => 1,
Second => -1,
others => 0);
procedure Foo is
subtype Acceleration is Mks_Type
with Dimension => ("m/sec^2", 1, 0, -2, others => 0);
G : constant Acceleration := 9.81 * M / (S ** 2);
T : Time := 10.0 * S;
Distance : Length;
begin
Distance := 0.5 * G * T ** 2;
Put (Distance, Aft => 2, Exp => 0);
end Foo
Object Pascal (Delphi)
-Ruby
-Smalltalk
-Common Lisp
-Haskell
F#
[<Measure>] type kg // declaration of base unit types
[<Measure>] type m
[<Measure>] type s
let mass = 2.0<kg>
let gravity = 9.81<m/s^2>
let force = mass * gravity // 19.62<kg m/s^2>
[<Measure>] type N = kg m/s^2 // declaration of derived unit type
let force2 = 19.62<N> // same as 'force'
Web Assembly text format
-LLVM IR
-Assembly
-A
Rust
let someChar = 'T';
// suporta 4 bytes unicode \u{0000}
Go
var someRune = 'T'
// go chama de runes
// suporta 4 bytes unicode \u0000
C++
auto someChar = 'T';
char oitoBits;
wchar_t trintaEDoisBits; // mas no windows é só 16 bits
char16_t dezesseisBits;
char32_t trintaEDoisBits;
char8_t oitoBits; // C++11
Objective-C
NSNumber* someChar = @'T';
NSNumber* someChar = [NSNumber numberWithChar:'T'];
Swift
// Use strings com apenas um caractere
// pode usar a notação \u{n}
// onde n is um número com 1 a 8 dígitos hexadecimais
Kotlin
var someChar = 'T'
// suporta 2 bytes unicode '\u0000' - '\uFFFF'
Java
var someChar = 'T';
// suporta 2 bytes unicode '\u0000' - '\uFFFF'
// e em alguns métodos que aceitam int pode usar até '\u10FFFF'
C#
var someChar = 'T';
// suporta 2 bytes unicode '\u0000' - '\uFFFF'
// ou notação em hexadecimal '\x0000'
Dart
TypeScript
JavaScript
// só usa strings
// não possui chars
ActionScript
// só usa strings
// não possui chars
Python
# Usa strings com apenas um caractere
PHP
VBA / VB6
Dim someChar: someChar = Chr(0)
' suporta 8 bits até Chr(255)
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Suporte a Unicode é o que mais pesou nesta classificação. Rust possui apenas um tipo que suporta até 32 bits, e C++ possui um para cada tamanho. Não sei até que ponto isso é vantagem. Também fiquei em dúvida se ter um tipo exclusivo para caracteres é vantajoso. Vou considerar que sim, embora não tenha feito nenhum benchmark. Objective-C possui dois tipos, o próprio e o herdado do C. Provavelmente VB6 foi descontinuado antes de existir Unicode, suportando apenas ASCII...
Rust
// tipo &str
let simples = "A primeira faz \"tchan\" e só";
let calvinHarris = "how deep\nis your love"; // 2 linhas
// várias linhas
let josePauloPaes = "Meu amor é simples, Dora,
Como a água e o pão.
Como o céu refletido
Nas pupilas de um cão.";
// concatenação
let leminski = concat!("Merda é veneno.",
"No entanto, não há nada",
"que seja mais bonito",
"que uma bela cagada.",
"Cagam ricos, cagam pobres,",
"cagam reis e cagam fadas.",
"Não há merda que se compare",
"à bosta da pessoa amada."
);
// tipo String
let simples = "A primeira faz \"tchan\" e só".to_string();
let raw_string = r"escape not \n processed";
let raw_string = r#"escape not " processed"#; // can also use other delimiters if needed
let integer_array = b"will be stored as an [u8] array";
let raw_integer_array = br"will be stored as an [u8] array with unescaped characters"
Go
dupla := "A segunda faz 'tchun'"
rawString := `A primeira faz "tchan". A segunda faz 'tchun'`
calvinHarris := "how deep\nis your love" // 2 linhas
// concatenação
josePauloPaes := "Meu amor é simples, Dora,\n" +
"Como a água e o pão.\n" +
"\n" +
"Como o céu refletido\n" +
"Nas pupilas de um cão."
// várias linhas
leminskiTemplate := `Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.`
emoji := "😍"
clustered := "\u1F60D" // code point
clustered := "\U0001F60D" // code point
bytes := "\xf0\x9f\x98\x8d"
// string é imutável, então seus métodos retornam novas instâncias
beeGees := strings.ReplaceAll(calvinHarris, "love", "looove")
strings.ToUpper("Gritando") // retorna "GRITANDO"
C++
auto cString = "mãe d'água";
auto cStringEscape = "A primeira faz \"tchan\"";
auto rawString = R"(A segunda faz "tchun")";
auto html = R"(<em class="especial">ênfase</em>)";
auto meuSeparador = R"meuSeparador(aa)meuSeparador";
auto meuSeparador = R"meuSeparador( )" )meuSeparador"; // FIXME highlighter raw string
auto calvinHarris = "how deep\nis your love"; // 2 linhas
auto pareceMasNaoE = "começa e \
termina na mesma linha?"; // 1 linha apenas
// várias linhas
auto josePauloPaes = "Meu amor é simples, Dora,\n\
Como a água e o pão.\n\
\n\
Como o céu refletido\n\
Nas pupilas de um cão.";
// várias linhas
auto leminski = R"(Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.)";
// concatenação
// TODO
Objective-C
NSString* simples = @"";
NSMutableString* mutavel = @"";
char* cString = "";
Swift
let simples = "A primeira faz \"tchan\" e só"
let calvinHarris = "how deep\nis your love" // 2 linhas
// concatenação - única maneira de usar várias linhas antes de swift 4
let josePauloPaes = "Meu amor é simples, Dora,\n" +
"Como a água e o pão.\n" +
"\n" +
"Como o céu refletido\n" +
"Nas pupilas de um cão."
// várias linhas (swift 4+)
let leminskiTemplate = """Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada."""
let leadingWhitespace = """
Sem leading (alinhado com a última linha)
Com um tab de leading
Sem leading (alinhado com a última linha)
"""
let multiplier = 3
let stringInterpolada = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
let emoji = "😍";
let combined = "\u{D83D}\u{DE0D}"
let clustered = "\u{1F60D}"
// string é imutável, então seus métodos retornam novas instâncias
let beeGees = calvinHarris.replacingOccurrences(of: "love", with: "looove")
"Gritando".uppercaseString // retorna 'GRITANDO'
Kotlin
val simples = "A primeira faz \"tchan\" e só"
val calvinHarris = "how deep\nis your love" // 2 linhas
// concatenação
val josePauloPaes = "Meu amor é simples, Dora,\n" +
"Como a água e o pão.\n" +
"\n" +
"Como o céu refletido\n" +
"Nas pupilas de um cão."
// várias linhas
val leminskiTemplate = """Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada."""
val leadingWhitespace = """
|Sem leading
| Com leading
|Sem leading
""".trimMargin()
// caso padrão de trimMargin("|")
// TODO
Java
var simples = "A primeira faz \"tchan\" e só";
var calvinHarris = "how deep\nis your love"; // 2 linhas
// concatenação
var josePauloPaes = "Meu amor é simples, Dora,\n" +
"Como a água e o pão.\n" +
"\n" +
"Como o céu refletido\n" +
"Nas pupilas de um cão.";
// várias linhas - java 14+
var leminskiTemplate = """Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.""";
var leadingWhitespace = """
Sem leading (alinhado com a última linha)
Com um tab de leading
Sem leading (alinhado com a última linha)
""";
C#
var simples = "A primeira faz \"tchan\"";
var dupla = @"A segunda faz ""tchun""";
var interpolated = $"A segunda faz \"tchun\"";
var calvinHarris = "how deep\nis your love"; // 2 linhas
// concatenação
var josePauloPaes = "Meu amor é simples, Dora,\n" +
"Como a água e o pão.\n" +
"\n" +
"Como o céu refletido\n" +
"Nas pupilas de um cão.";
// várias linhas
var leminskiTemplate = @"Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.";
var multiInterpolated = $@"{a}
{b}";
var multiplier = 3;
var stringInterpolada = $"{multiplier} times 2.5 is {multiplier * 2.5}";
var emoji = "😍";
var combined = "\uD83D\uDE0D";
var clustered = "\x1F60D";
// string é imutável, então seus métodos retornam novas instâncias
var beeGees = calvinHarris.Replace("love", "looove");
"Gritando".ToUpper(); // retorna 'GRITANDO'
Dart
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";
var s1 = 'String '
'concatenation'
" works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
var s = r'In a raw string, not even \n gets special treatment.';
// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
var sb = StringBuffer();
sb
..write('Use a StringBuffer for ')
..writeAll(['efficient', 'string', 'creation'], ' ')
..write('.');
var fullString = sb.toString();
TypeScript
JavaScript
'use strict';
let simples = 'A primeira faz "tchan"';
let dupla = "A segunda faz 'tchun'";
let duplaTemplate = `A primeira faz "tchan". A segunda faz 'tchun'`;
const iara = "mãe d'água";
const modoDificil = 'O\'Reilly';
let html = '<em class="especial">ênfase</em>';
let calvinHarris = 'how deep\nis your love'; // 2 linhas
let pareceMasNaoE = 'começa e \
termina na mesma linha?'; // 1 linha apenas
// várias linhas
let josePauloPaes = 'Meu amor é simples, Dora,\n\
Como a água e o pão.\n\
\n\
Como o céu refletido\n\
Nas pupilas de um cão.';
// várias linhas
let leminskiTemplate = `Merda é veneno.
No entanto, não há nada
que seja mais bonito
que uma bela cagada.
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.`;
let multiplier = 3;
let stringInterpolada = `${multiplier} times 2.5 is ${multiplier * 2.5}`;
let emoji = '😍';
let es5 = '\uD83D\uDE0D'; // code units / surrogates
let es6 = '\u{1F60D}'; // code point
// string é imutável, então seus métodos retornam novas instâncias
let beeGees = calvinHarris.replace('love', 'looove');
'Gritando'.toUpperCase(); // retorna 'GRITANDO'
ActionScript
var simples = 'A primeira faz "tchan"';
var dupla = "A segunda faz 'tchun'";
const iara = "mãe d'água";
const modoDificil = 'O\'Reilly';
var html = 'ênfase';
var calvinHarris = 'how deep\nis your love'; // 2 linhas
var pareceMasNaoE = 'começa e \
termina na mesma linha?'; // 1 linha apenas
// concatenação
var josePauloPaes = 'Meu amor é simples, Dora,\n' +
'Como a água e o pão.\n' +
'\n' +
'Como o céu refletido\n' +
'Nas pupilas de um cão.';
// várias linhas
var leminskiTemplate = 'Merda é veneno.\n\
No entanto, não há nada\n\
que seja mais bonito\n\
que uma bela cagada.\n\
Cagam ricos, cagam pobres,\n\
cagam reis e cagam fadas.\n\
Não há merda que se compare\n\
à bosta da pessoa amada.';
var emoji = '😍';
var es5 = '\uD83D\uDE0D'; // code units / surrogates
// string é imutável, então seus métodos retornam novas instâncias
var beeGees = calvinHarris.replace('love', 'looove');
'Gritando'.toUpperCase(); // retorna 'GRITANDO'
Python
simples = 'A primeira faz "tchan"'
dupla = "A segunda faz 'tchun'"
iara = "mãe d'água"
modoDificil = 'O\'Reilly'; # TODO verificar isso
html = '<em class="especial">ênfase</em>'
calvinHarris = 'how deep\nis your love'; # 2 linhas
pareceMasNaoE = 'começa e \
termina na mesma linha?'; # 1 linha apenas TODO verificar isso
# várias linhas
josePauloPaes = 'Meu amor é simples, Dora,\n\
Como a água e o pão.\n\
\n\
Como o céu refletido\n\
Nas pupilas de um cão.'; # TODO verificar isso
# várias linhas
leminskiTemplate = '''
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada.'''
# várias linhas
leminskiTemplate2 = """
Cagam ricos, cagam pobres,
cagam reis e cagam fadas.
Não há merda que se compare
à bosta da pessoa amada."""
# string é imutável, então seus métodos retornam novas instâncias
beeGees = calvinHarris.replace('love', 'looove');
'Gritando'.upper(); # retorna 'GRITANDO'
PHP
VBA / VB6
Option Explicit
Dim simples As String
simples = "A primeira faz ""tchan"""
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
// TODO melhorar isso
let mut vector:Vec<_>;
vector.push("Terminou.");
vector.push(" Só que não");
vector
.chars()
.collect();
Go
var stringBuilder strings.Builder
stringBuilder.WriteString("Terminou")
stringBuilder.WriteString(" Só que não")
stringBuilder.String()
C++
#include <sstream>
std::ostringstream outputStringStream;
outputStringStream << "Terminou." << " Só que não.";
outputStringStream.str();
Objective-C
// TODO NSMutableString
Swift
// supostamente var string
// ao invés de let string
Kotlin
var stringBuilder = new StringBuilder()
stringBuilder.append("Terminou.")
stringBuilder.append(" Só que não.")
stringBuilder.toString()
Java
var stringBuilder = new StringBuilder();
stringBuilder.append("Terminou.");
stringBuilder.append(" Só que não.");
stringBuilder.toString();
// StringBuilder não é thread safe
// Existe também a classe StringBuffer, que é
C#
var stringBuilder = new StringBuilder();
stringBuilder.Append("Terminou.");
stringBuilder.Append(" Só que não.");
stringBuilder.ToString();
Dart
TypeScript
JavaScript
-ActionScript
-Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
let vazia:[i32; 0] = [];
// uma dimensão
let mut preAlocada:[i32; 10];
preAlocada = [0; 17];
let prePopulada = ["p", "r", "e"];
let prePopuladaT:[&str; 3] = ["p", "o", "p"];
const linhas:usize = 2;
const colunas:usize = 4;
// multidimensional
let mdPreAlocada:[[u8; colunas]; linhas];
let mdPrePopulada = [
[0, 1, 2, 3],
[4, 5, 6, 7]
];
preAlocada[5] = 16000;
let indice0 = prePopulada[0];
let two = mdPrePopulada[0][2];
for valor in prePopulada.iter() {
//
}
for (indice, valor) in prePopulada.iter().enumerate() {
// indice e valor
}
let tamanho = mdPrePopulada.len();
// TODO comparar arrays
Go
vazia := [0]int{}
var vazia2 [0]int
// uma dimensão
var preAlocada [10]int
// não é possível redimensionar uma array em Go
prePopulada := [3]string{"p", "r", "e"}
var prePopuladaT [3]string = [3]string{"p", "o", "p"}
// tem que ser constantes
const linhas = 2
const colunas = 4
// multidimensional
var mdPreAlocada [linhas][colunas]uint8
mdPrePopulada := [linhas][colunas]uint8 {
{0, 1, 2, 3},
{4, 5, 6, 7}, // , no final não é um erro, go requer
}
preAlocada[5] = 16000
indice0 := prePopulada[0]
two := mdPrePopulada[0][2]
for indice, valor := range prePopulada {
//
}
tamanho := len(mdPrePopulada)
C++
// TODO
std::Array arrayCpp;
int arrayCPreAlocada[10];
Objective-C
int arrayCPreAlocada[10];
// uma dimensão
NSArray* prePopulada = @[@"p", @"r", @"e"];
NSArray* prePopuladaAntiga = [NSArray arrayWithObjects:@"o", @"l", @"d", nil];
int linhas = 2;
int colunas = 4;
// multi dimensional
int arrayCMdPreAlocada[linhas][colunas];
int arrayCMdPrePopulada[linhas][colunas] = {
{0, 1, 2, 3},
{4, 5, 6, 7}
};
int arrayCMdPrePopulada2[linhas][colunas] = {0, 1, 2, 3, 4, 5, 6, 7};
for (NSString* valor in prePopulada) {
//
}
Swift
var vazia = [Int]()
var vazia2:[Int] = []
var vazia3:Array<Int> = Array<Int>()
// uma dimensão
var preAlocada = [Int](count: 10, repeatedValue: 0)
preAlocada = [Int](count: 17, repeatedValue: 0)
var prePopulada = ["p", "r", "e"]
var prePopuladaT:[String] = ["p", "o", "p"]
let linhas = 2
let colunas = 4
// multi dimensional
var mdPrePopulada:[[Int]] = [
[0, 1, 2, 3],
[4, 5, 6, 7]
]
preAlocada[5] = 16000;
preAlocada[6...8] = [4, 20, 8];
let indice0 = prePopulada[0];
let two = mdPrePopulada[0, 2];
for valor in prePopulada {
//
}
for (indice, valor) in prePopulada.enumerated() {
// indice e valor
}
let tamanho = mdPrePopulada.count
// também temos a propriedade .empty
// e os métodos insert e removeAtIndex
// TODO testar coisas não cobertas na documentação
// comparar arrays
Kotlin
// uma dimensão
var preAlocada = IntArray(10)
preAlocada = IntArray(17)
val linhas = 2
val colunas = 4
// multi dimensional
var mdPreAlocada = Array(linhas, { IntArray(colunas) })
// TODO
Java
// uma dimensão
int[] preAlocada = new int[10];
preAlocada = new int[17];
String[] prePopulada = {"p", "r", "e"};
int linhas = 2;
int colunas = 4;
// multi dimensional
byte[][] mdPreAlocada = new byte[linhas][colunas];
byte[][] mdPrePopulada = {
{0, 1, 2, 3},
{4, 5, 6, 7}
};
preAlocada[5] = 16000;
String indice0 = prePopulada[0];
byte two = mdPrePopulada[0][2];
for (String valor : prePopulada) {
//
}
int tamanho = mdPrePopulada.length;
// TODO comparar arrays
// pode mas não faça
// acho que tem pra quem vem do C
float podeMasNaoFaca[];
float[][] podeMasNaoFaca = {{}};
float[] podeMasNaoFaca[] = {{}};
float podeMasNaoFaca[][] = {{}};
C#
// uma dimensão
int[] preAlocada = new int[10];
preAlocada = new int[17];
String[] prePopulada = {"p", "r", "e"};
int linhas = 2;
int colunas = 4;
// multi dimensional
byte[,] mdPreAlocada = new byte[linhas, colunas];
byte[,] mdPrePopulada = {
{0, 1, 2, 3},
{4, 5, 6, 7}
};
byte[][] arrayDeArraysPreAlocada = new byte[4][];
arrayDeArraysPreAlocada[0] = new byte[4];
// ...
byte[][] arrayDeArraysPrePopulada = {
new byte[] {0, 1, 2, 3},
new byte[] {4, 5, 6, 7}
};
preAlocada[5] = 16000;
String indice0 = prePopulada[0];
byte two = mdPrePopulada[0, 2];
foreach (var valor in prePopulada) {
//
}
var tamanho = mdPrePopulada.Length
// TODO exemplos com var
// comparar arrays
Dart
TypeScript
JavaScript
let vazia = [];
// uma dimensão
let preAlocada = new Array(10);
preAlocada = new Array(17);
let prePopulada = ["p", "r", "e"];
let linha = 0;
let coluna = 2;
// multi dimensional
let mdPrePopulada = [
[0, 1, 2, 3],
[4, 5, 6, 7]
];
preAlocada[5] = 16000;
let indice0 = prePopulada[0];
let two = mdPrePopulada[linha][coluna];
for (let valor of prePopulada) {
//
}
let tamanho = mdPrePopulada.length;
// TODO comparar arrays
ActionScript
var vazia = [];
// uma dimensão
var preAlocada:Array = new Array(10);
preAlocada:Array = new Array(17);
var prePopulada:Array = ["p", "r", "e"];
var linha:uint = 0;
var coluna:uint = 2;
// multi dimensional
var mdPrePopulada:Array = [
[0, 1, 2, 3],
[4, 5, 6, 7]
];
// O tipo Array não é capaz de restringir
// o tipo de seu conteúdo. Podemos
// inclusive armazenar tipos misturados
// Portanto não é 100% seguro especificar
// um tipo quando obtemos o valor de uma Array.
preAlocada[5] = 16000;
var indice0 = prePopulada[0];
var two = mdPrePopulada[linha][coluna];
for (var valor in prePopulada) {
//
}
var tamanho = mdPrePopulada.length;
Python
PHP
VBA / VB6
Dim vazia() As Integer
Dim preAlocada(9) As Integer
' Aloca espaço na array vazia
' É possível usar variáveis ao invés de literais fixas
ReDim Preserve vazia(0 To 9)
preAlocada(5) = 1600
Dim valor As Integer
For Each valor In prePopulada
'
Next
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
let mut lista:Vec<i32> = vec![];
lista.push(1);
Go
var lista []int // em go se chamam slices
listaPreAlocada := make([]int, 10)
listaPrePopulada := := []string{"p", "r", "e"}
// slices são imutáveis, assim como strings
lista = append(lista, 1)
listaPreAlocada = append(listaPreAlocada, 1)
// Go não tem uma função para remover itens
// Temos duas opções
// remover um item sem manter ordem (tempo constante)
// copia o último item sobre o item que vai ser removido
pre[i] = pre[len(pre)-1]
pre[len(pre)-1] = ""
// remover um item mantendo a ordem (curva tempo n)
// move todos os item para a esquerda
copy(pre[i:], pre[i+1:])
pre[len(pre)-1] = ""
// apaga o último item
pre = pre[:len(pre)-1]
C++
std::vector<int> lista;
lista.push_back(1);
Objective-C
NSMutableArray* lista;
Swift
var lista = [Int]() // arrays são "listas"
lista.append(1)
Kotlin
// temos List (listOf) e MutableList (mutableListOf)
var lista = mutableListOf<int>()
lista.add(1)
Java
// List é uma interface com ArrayList e LinkedList
List<Integer> lista = new ArrayList<Integer>();
lista.add(1);
C#
List<int> lista;
lista.Add(1);
Dart
TypeScript
JavaScript
let lista = []; // arrays são "listas"
lista.push(1);
ActionScript
var lista = []; // arrays são listas
lista.push(1);
// também temos Vector, que é tipado e tem outras otimizações
var lista:Vector.<String>
lista = new Vector.<String>();
var listaPreAlocada:Vector.<String> = new Vector.<String>(10);
var listaTamanhoFixo:Vector.<String> = new Vector.<String>(10, true);
var listaPrePopulada:Vector.<String> = new <String>['p', 'r', 'e'];
listaPreAlocada.push(1);
listaTamanhoFixo.push(1); // erro
listaPrePopulada.push(1);
Python
PHP
VBA / VB6
Dim lista As Collection
Set lista = New Collection
lista.Add 1
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
// TODO
// &'static str statically allocated lives inside the program binary code
// stack by default
// heap
// String
// Box<T>
// Vec<T>
// growable on heap
Go
C++
// TODO
// tipos na stack por padrão
// tipos com new na heap
// enums?
// closures?
Objective-C
// TODO
// structs na stack?
// e classes?
// enums?
// closures? tem closures?
Swift
// TODO
// primitive on stack
// structs e enums value types - stack
// classes and closures on the heap
Kotlin
Java
// tipos primitivos na stack
int i = 10;
// tipos de referência na heap
String s = "Na heap"; // TODO verificar string heap
Object o = new Object();
// enums tb?
C#
// tipos valor na stack
// tipos primitivos na stack
int i = 10;
// enums na stack
// structs às vezes na stack
AStruct a;
Point p;
unsafe {
byte* ponteiroDeArray = stackalloc byte[1024];
}
// nullables na stack
// tipos de referência na heap
// class, interface, array e delegate
string a = "Na heap"; // TODO verificar string heap
object o = new object();
Dart
TypeScript
JavaScript
// Não existe uma definição
// na especificação
// A máquina virtual pode ou não
// alocar tipos primitivos
// e tipos de referência
// tanto na stack quanto na heap
ActionScript
// Mesmo tipos primitivos
// são objetos, porém
// imutáveis.
// não está claro se usa
// stack ou não
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust - Ownership e Lifetimes
Go - Mark and Sweep GC
C++ - RAII
// smart pointers
Objective-C - Reference Counting
// ARC
Swift - Reference Counting
// ARC
Kotlin
Java - Mark and Sweep GC
// weak e ghost references
C# - Mark and Sweep GC
// weak references
Dart
TypeScript
JavaScript - Mark and Sweep GC
// weak maps
ActionScript
// weak references
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
// TODO
let p:*const i32 = ptr::null();
let p:*mut i32 = ptr::null();
let x = 90;
let raw = &x as *const i32;
let mut y = 95;
let raw_mut = &mut y as *mut i32;
let points_at = unsafe { *raw };
unsafe {
let points_at = *raw;
}
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
}
Go
intOriginal := 90
segundoIntOriginal = 95
ponteiroDeInt := &intOriginal
fmt.Println(*ponteiroDeInt) // 90
ponteiroDeInt = &segundoIntOriginal
fmt.Println(*ponteiroDeInt) // 95
var outroPonteiroDeInt = &intOriginal
var maisUmPonteiroDeInt int*
aindaMaisUmPonteiroDeInt := new(int)
aindaMaisUmPonteiroDeInt = &intOriginal
*ponteiroDeInt = 5
fmt.Println(*ponteiroDeInt) // 5
// TODO
// const int* ponteiroDeInt = &intOriginal;
// podemos atribuir endereços aleatórios de memória para ponteiros ??
// ponteiro de array
// ponteiros para funções?
// void* ponteiroGenerico;
// int** ponteiroDePonteiro;
C++
// variável tipo ponteiro
// ponteiros são nullable e podemos usar
// o valor especial nullptr, que representa
// um endereço de memória inválido
int* newNull{nullptr}; // C++11
// versões antigas usam o valor NULL, que é 0
// por baixo dos panos, também representando
// um endereço de memória inválido
int* oldNull{NULL}; // old
// existe ainda um tipo nullptr_t, que só pode
// receber nullptr e não aceita nenhum outro valor
// não imagino muitos usos para ele fora fazer
// piadinhas com o Elvis ;)
std::nullptr_t o_onlyNuuull{nullptr}; // C++11
// variáveis comuns tipo int
int intOriginal{90};
int segundoIntOriginal{95};
// variável tipo ponteiro de int (int*) aponta
// para variável comum tipo int
// seu valor é um inteiro 32 ou 64 bits, representando
// o endereço de memória de intOriginal, que podemos
// obter usando o operador &
int* ponteiroDeInt{&intOriginal};
// para acessarmos o valor da variável através
// do ponteiro, usamos o operador *
cout << "valor de int " << *ponteiroDeInt << endl; // 90
// se fizermos ele apontar para outra variável, seu valor muda
ponteiroDeInt = &segundoIntOriginal;
cout << "valor de int " << *ponteiroDeInt << endl; // 95
// também podemos pegar endereços de memória através de outros
// ponteiros, pois como disse acima, seus valores são numéricos
// 32 ou 64 bits
int* ponteiroDeSegundoInt{ponteiroDeInt};
cout << "valor de int " << *ponteiroDeSegundoInt); // 95
// TODO
// podemos atribuir enderecos aleatórios de memória para ponteiros :(
// podemos marcar o ponteiro como const, mas isso
// NÃO PREVINE QUE ELE APONTE PARA VARIÁVEIS DIFERENTES!!!
// TODO verificar se previne a modificação dos objetos apontados
const int* ponteiroConst{&intOriginal}; // 90
ponteiroConst = &segundoIntOriginal; // 95
// depois que não precisarmos mais dos ponteiros
// precisamos APAGÁ-LOS ANTES QUE SAIAM DE ESCOPO,
// para evitar que fiquem perdidos na memória
// sem podermos acessá-los (dangling pointers)
// devemos fazer isso apenas para ponteiros null
// ou ponteiros de objetos alocados na heap
// através do operador new
delete newNull;
delete oldNull;
// o gerenciamento manual dos ponteiros com delete
// não é recomendado, e existem classes que os apagam
// automaticamente e de maneira determinística assim
// que saem de escopo
auto ponteiroSmart{std::make_unique<int>(1000)};
auto ponteiroSmartShared{std::make_shared<int>(1001)};
// TODO old boost smart pointers
// embora isso não seja necessário para ponteiros int*
// existe uma outra característica dessas classes, que
// é não permitir o valor nullptr, uma vez que seu tipo
// é especificado
auto semNullPointer{std::make_unique<int>(nullptr)}; // erro :)
// embora NULL seja um valor váido para int*, uma vez que
// NULL na verdade é 0 por baixo dos panos
auto semNullPointer{std::make_unique<int>(NULL)}; // funciona!
// além disso, não é possível mudar o endereço para o qual
// esse tipo de ponteiro aponta uma segunda vez
auto semSegundaChance{std::make_unique<int>(1000)};
// semSegundaChance = &intOriginal; // erro
// semSegundaChance = ponteiroDeInt; // erro
// TODO referências
// referências não são ponteiros oficialmente segundo
// a especificação
// não podem ser nullptr nem NULL
int& ponteiroRefNullPointer{nullptr}; // erro :)
int& ponteiroRefNULL{NULL}; // erro :)
int& ponteiroRef{intOriginal}; // 90
ponteiroRef = segundoIntOriginal; // 95
const int& ponteiroConstRef{intOriginal}; // 90
ponteiroConstRef = segundoIntOriginal; // erro, não é mutável :)
// não pode pegar o endereço de referências
// ponteiros para arrays
// ponteiros para funções
// void*
// ponteiros de ponteiros
// referências de ponteiros
Objective-C
// variável tipo ponteiro
// ponteiros são nilable e podemos usar
// o valor nil, que representa
// um endereço de memória inválido
int* nilPointer = nil; // Objective-C
// é possível usar do C o valor NULL, que é 0
// por baixo dos panos, também representando
// um endereço de memória inválido
int* cNullPointer = NULL; // C
Swift
var nilPointer:UnsafeMutablePointer<int> = nil
// variáveis comuns tipo int
let intOriginal = 90
let segundoIntOriginal = 95
// int* ponteiroDeInt = &intOriginal;
var ponteiroDeInt:UnsafeMutablePointer<Int> = &intOriginal
print(ponteiroDeInt) // 90
ponteiroDeInt = &segundoIntOriginal
print(ponteiroDeInt) // 95
let ponteiroDeSegundoInt = ponteiroDeInt
print(ponteiroDeSegundoInt) // 95
// const int* ponteiroDeInt = &intOriginal;
var ponteiroConst:UnsafePointer<Int> = &intOriginal
ponteiroConst = &segundoIntOriginal
// mais ou menos const int& ponteiroConstRef; ??
let ponteiroConstRef:UnsafePointer<Int> = &intOriginal
// TODO
// podemos atribuir endereços aleatórios de memória para ponteiros ??
// ponteiro de array
// ponteiros para funções?
// void* ponteiroGenerico;
var ponteiroGenerico:UnsafePointer<Void>
// int** ponteiroDePonteiro;
let ponteiroDePonteiro = AutoreleasingUnsafeMutablePointer<Int?> // tem que ser nullable?
Kotlin
// possui uma classe CPointer
// para interop com C apenas
Java
-C#
using System;
namespace MarcoLuglio.PonteirosExample {
class MainClass {
public static void Main(string[] args) {
// C# requer um contexto unsafe para utilização de ponteiros
// Existem vários contexto que podem ser marcados como unsafe,
// mas vou mostrar apenas o bloco de código unsafe
unsafe {
// TODO não pode null pointer
// variáveis comuns tipo int
int intOriginal = 90;
int segundoIntOriginal = 95;
// variável tipo ponteiro de int (int*)
// aponta para variável comum tipo int
// seu valor é um inteiro 64 bits (long), representando
// o endereço de memória de intOriginal, que podemos obter
// usando o operador &
int* ponteiroDeInt = &intOriginal;
// para acessarmos o valor da variável comum
// através do ponteiro, usamos o operador *
Console.WriteLine(@"valor de int {0} ", *ponteiroDeInt); // 90
// se fizermos ele apontar para outra variável, seu valor muda
ponteiroDeInt = &segundoIntOriginal;
Console.WriteLine(@"valor de int {0} ", *ponteiroDeInt); // 95
// também podemos pegar endereços de memória através de outros
// ponteiros, pois como disse acima, seus valores são números
// tipo long
int* ponteiroDeSegundoInt = ponteiroDeInt;
Console.WriteLine(@"valor de int {0} ", *ponteiroDeSegundoInt); // 95
// não é possível iniciar um ponteiro especificando diretamente
// um endereço de memória
int* enderecoQualquer = 10; // erro TODO verificar qual o erro
// variável tipo ponteiro de buffer de bytes (bytes*)
// aponta para array de bytes pré-alocada na stack
// seu valor é igual ao endereço de memória da array de bytes
byte* ponteiroDeArray = stackalloc byte[1024];
// atribuímos o valor 5 para o índice 0 da array na stack
// e o valor 11 para o índice 729
// para acessarmos os índices, usamos o operador []
ponteiroDeArray[0] = 5;
ponteiroDeArray[729] = 11;
// para acessarmos os valores nos índices, usamos o operador []
byte indice0 = ponteiroDeArray[0];
byte indice729 = ponteiroDeArray[729];
Console.WriteLine(
@"valores {0} e {1}",
indice0, // 0
indice729 // 1
);
// Notem que não há nada no ponteiro que indique se tratar de uma array!
// Então como o compilador consegue diferenciar entre um ponteiro
// para um byte comum e para uma array de bytes?
// Ele não consegue! E dependendo do que você for fazer, nem vai lançar
// uma exceção, apenas usar um valor incorreto.
// Portanto cuidado ao utilizar ponteiros.
// Por exemplo, seria válido (embora não recomendado) fazer isso:
// byte byteOriginal = 37;
// ponteiroDeArray = &byteOriginal;
// variável tipo ponteiro desconhecido
// aponta para qualquer tipo de variável
// quando null, seu valor é igual a 0, representando um endereço
// de memória inválido
// neste estado, *ponteiroGenerico lança NullReferenceException
void* ponteiroGenerico = null;
// esse tipo de ponteiro não é recomendado pois perde
// a informação sobre o tipo para o qual ele aponta
// essa característica é usada para fazer casts forçados
// neste estado, seu valor é igual ao endereço de memória de intOriginal
ponteiroGenerico = &intOriginal;
// para acessarmos o valor apontado por esse tipo de ponteiro
// é necessário fazer um cast para o tipo que se deseja
Console.WriteLine(@"valor de void {0} ", (*(int*)ponteiroGenerico)); // 90
// agora seu valor é igual ao endereço de memória da array de bytes
ponteiroGenerico = ponteiroDeArray;
// podemos acessar os valores da array apontada pelo ponteiro
// fazendo o cast apropriado
// a mesma recomendação sobre o operador [] vale aqui, o compilador
// não consegue identificar se o valor é uma array ou um byte simples
// e vai acreditar no que você pedir
Console.WriteLine(@"valor de void*[0] {0} ", ((byte*)ponteiroGenerico)[0]); // 5
// variável tipo ponteiro de ponteiro de int (int**)
// aponta para variável do tipo ponteiro de int
// seu valor é igual ao endereço de memória de ponteiroGenerico
// esse tipo de ponteiro é utilizado quando não desejamos copiar o
// ponteiro original ao passá-lo para outras funções
// uma vez que, como o ponteiro é um valor long, é passado por cópia
// para as funções!
int** ponteiroDePonteiro = (int**)&ponteiroGenerico;
// para acessarmos o valor no final da cadeia, usamos o operador * duas vezes
Console.WriteLine(@"valor de ponteiro {0} ", **ponteiroDePonteiro);
// se usarmos apenas uma vez, obteremos o ponteiro intermediário
Console.WriteLine(
@"endereço apontado pelo ponteiro intermediário {0} ",
*ponteiroDePonteiro
);
// novamente, o compilador não pode ajudar muito caso você cometa um erro
// por exemplo, se esquecermos do operador & estaremos pegando o endereço
// do valor final, ao invés do endereco do ponteiro intermediário, porém,
// estamos dizendo ao compilador que é o endereço de um ponteiro legítimo
ponteiroDePonteiro = (int**)ponteiroGenerico;
// e só será lançado um erro se tentarmos acessar o valor final na cadeia
// pois estaremos tentando usar um valor inteiro como se fosse um ponteiro
Console.WriteLine(@"lança NullReferenceException {0} ", **ponteiroDePonteiro);
// embora possamos criar ponteiros de ponteiros de ponteiros, acho que não
// há uma aplicação muito prática pra isso
int*** ponteiroDesnecessario;
// TODO structs e fixed {}
}
// os ponteiros são desalocados após o término do contexto unsafe
// não é necessário deletar os ponteiros manualmente
}
}
}
Dart
TypeScript
JavaScript
-ActionScript
-Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Não sei ao certo como avaliar esse tópico. Certamente não é a mesma coisa que gerenciamento de memória avaliado logo acima.
Todas as linguagens permitem void*
de alguma maneira
Swift possui nomes mais claros em relação ao que cada ponteiro significa, embora a relação com suas versões em C não sejam fáceis de adivinhar. Não é necessário utilizar operadores diferentes para interagir com ponteiros.
C# tenta evitar ao máximo o uso de ponteiros para tarefas corriqueiras. Mas faz muito pouco em relação à C++ para impedir problemas com a utilização de ponteiros quando são necessários, e acaba sendo equivalente em segurança, embora de maneira diferente. As duas linguagens possuem recursos para impedir ponteiros null
, e para apagar os ponteiros quando saírem de escopo. C# delimita claramente um bloco isolado para trabalhar com ponteiros, mas não permite marcá-los como const
. C++ ainda tem o operador delete
, mas você não precisa usá-lo.
Objective-C usa ponteiros estilo C. Requer muitas vezes que os objetos sejam alocados e depois inicializados num passo diferente. Como muitas coisas nessa linguagem, mistura sintaxes das duas linguagens. Por exemplo, ivars e properties.
Rust
// tipo simples
type Name = String;
// tipo função
// TODO testar
// type StrategyFunctionPointer = fn(i32) -> i32;
Go
// tipo simples
type T1 = T2
// novo tipo baseado em T2
type T1 T2
// tipo função
type StrategyFunctionPointer func(int) int
C++
// tipo simples
using size_t = unsigned int;
typedef unsigned char BYTE; // old
// tipo função
using StrategyFunctionPointer = void(*)();
// ou
using StrategyFunction_t = void();
StrategyFunction_t* strategyFunctionPointer = f;
// ou
#include <type_traits>
using StrategyFunctionPointer = std::add_pointer<void()>::type;
// ou (old)
typedef void(*StrategyFunctionPointer)();
// só metodos ou funções tb?
Objective-C
// tipo simples
@compatibility_alias UICollectionViewController PSTCollectionViewController;
typedef unsigned char BYTE;
// tipo função
typedef void(*StrategyFunctionPointer)();
Swift
// tipo simples
typealias AudioSample = UInt16
// tipo função
typealias StrategyFunctionPointer = () -> ()
Kotlin
// tipo função
typealias StrategySignature = //
Java
-C#
// tipo simples
using R = N1.N2;
// tipo função
delegate void StrategyFunctionDelegate();
Dart
TypeScript
JavaScript
ActionScript
static const MyClass:Class = int;
var ert:* = new MyClass();
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
Go
C++
// TODO <=>
Objective-C
Swift
Kotlin
val max = if (a > b) {
a
} else {
b
}
Java
C#
Dart
var number = 10;
if (number > 0) {
// positivo
} else if (number < 0) {
// negativo
} else {
// zero
}
// logical operators
bool condition1 = true;
bool condition2 = true;
TypeScript
JavaScript
ActionScript
var number:int = 10;
if (number > 0) {
// positivo
} else if (number < 0) {
// negativo
} else {
// zero
}
// logical operators
var condition1:Boolean = true;
var condition2:Boolean = true;
// short circuit
if (condition1 && condition2) {
myTextField.appendText('both true');
}
// short circuit
if (condition1 || condition2) {
myTextField.appendText('both true');
}
if (condition1 != condition2) {
myTextField.appendText('both true');
}
if (condition1 == false) {
myTextField.appendText('both true');
}
if (!condition1) {
myTextField.appendText('both true');
}
Python
PHP
// TODO <=>
VBA / VB6
Dim number As Integer: number = 10
If Number > 0 Then
' positivo
ElseIf Number < 0 Then
' negativo
Else
' zero
End If
' logical operators
Dim condition1 As Boolean
Dim condition2 As Boolean
' short circuit
If condition1 And condition2 Then
'
' short circuit
If condition1 Or condition2 Then
'
If condition1 Xor condition2 Then
'
If condition1 <> condition2 Then
'
If condition1 = False Then
'
If Not condition1 Then
'
Ada
declare
number:Integer;
begin
number := 10;
if number > 0 then
-- positivo
elsif number < 0 then
-- negativo
else
-- zero
end if;
end;
-- logical operators
declare
condition1:Bool;
condition2:Bool;
begin
-- evaluates both conditions!
if condition1 and condition2 then
--
-- short circuit
if condition1 and then condition2 then
--
-- evaluates both conditions!
if condition1 or condition2 then
--
-- short circuit
if condition1 or else condition2 then
--
if condition1 xor condition2 then
--
if condition1 /= condition2 then
--
if condition1 = False then
--
if not condition1 then
--
end;
Object Pascal (Delphi)
var
number:Integer;
begin
number := 10;
if number > 0 then
// positivo
else if number < 0 then
// negativo
else
// zero
end;
// ou
var
number:Integer;
begin
number := 10;
if number > 0 then // positivo
begin
// multiline
end;
else if number < 0 then // negativo
begin
// multiline
end;
else // zero
begin
// multiline
end;
end;
// logical operators
var
condition1:Bool;
condition2:Bool;
begin
// short circuit
if condition1 and condition2 then
//
// short circuit
if condition1 or condition2 then
//
if condition1 xor condition2 then
//
if condition1 <> condition2 then
//
if condition1 = false then
//
if not condition1 then
//
end;
Ruby
number = 10
if number > 0
# positivo
elsif number < 0
# negativo
else
# zero
end
# TODO <=>
# logical
condition1 = true
condition2 = false
# short circuit
if condition1 && condition2
#...
# same as && but with lower precedence
if condition1 and condition2
#...
# short circuit
if condition1 || condition2
#...
# same as || but with lower precedence
if condition1 or condition2
#...
if condition1 ^ condition2
#...
if condition1 != condition2
#...
if condition1 == false
#...
if !condition1
#...
# same as ! but with lower precedence
if not condition1
#...
Smalltalk
Common Lisp
(let(
(number 10)
)
; if
; (if (condition) (then code))
; if / else
; (if (condition) (then code) (else code))
; if / else if... / else chain
; (if (condition)
; (then code)
; (if (else if condition)
; (then code)
; (if (else if condition)
; (then code)
; (else code)
; ))) ; close all ifs
(if (> number 0)
(print "positivo")
; else if
(if (< number 0)
(print "negativo")
; else
(print "zero")
))
; TODO
; (unless)
; (when)
; (cond)
)
Haskell
F#
Web Assembly text format
i32.const 0
;; change to positive number (true)
;; if you want to run the if block
(if
(then
i32.const 1
call $log ;; should log '1'
)
(else
i32.const 0
call $log ;; should log '0'
)
)
;; ou usar a instrução br
(loop $my_loop
;; if $i is less than 10 branch to loop
global.get $i
i32.const 10
i32.lt_s
br_if $my_loop
)
LLVM IR
if:
%cond = icmp eq i32 %a, %b
br i1 %cond, label %then, label %else
then:
ret i32 1 ;; or jump to label endIf
else:
ret i32 0
endIf:
Assembly
Rust
while i < 10 {
// ...
}
let mut optional = Some(0);
while let Some(i) = optional {
// use i here
}
// mesmo que while true {...}
loop {
//...
// to exit the loop call
break;
}
// no do while
// use loop + if break
Go
for i < 10 {
// ...
}
// TODO testar
for i := returnBoolOrNullable {
// ..
}
// equivalente à while true {...}
for {
//...
// to exit the loop call
break;
}
// no do while
// use for + if break
C++
Objective-C
Swift
while i < 10 {
// ...
}
// do while
repeat {
// ...
} while i < 10
Kotlin
while (i < 10) {
// ...
}
do {
// ...
} while (i < 10) // i is visible here!
Java
C#
Dart
TypeScript
JavaScript
while (i < 10) {
// ...
}
do {
// ...
} while (i < 10)
ActionScript
while (i < 10) {
// ...
}
do {
// ...
} while (i < 10)
Python
while i < 10:
# ...
while i < 10:
# ...
else:
# ...
PHP
VBA / VB6
While i < 10
'...
Wend
Ada
while i < 10 loop
-- ...
end loop;
-- equivalente à while true {...}
loop
-- ...
end loop;
Object Pascal (Delphi)
while i < 10 do
begin
// ...
end;
repeat
// ...
until i < 10;
Ruby
while i < 10
# ...
end
loop do
# ...
end
# until conditional [do]
# unlike “loop do”,
# here the “do” is optional
until conditional
# ...
end
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
for item in collection {
println!("{}", item);
}
Go
slice := []int{2, 3, 4}
for i, numero := range slice {
// os valores dentro de for each
// são cópias e não referências
}
dicionario := map[string]string{ "a": "apple", "b": "banana" }
for chave, valor := range dicionario {
// ordem não é garantida para maps
}
texto := "um texto"
for i, letra := range texto {
//
}
canal := make(chan int)
go func() {
canal <- 1
canal <- 2
canal <- 3
close(canal)
}()
for numero := range canal {
// se o canal for fechado
// for each bloqueia!?
}
C++
for (const auto &item : collection) { // C++ 11+
cout >> item;
}
// functor com contrutor implícito
struct Functor {
void operator()(const Item& item) {
cout >> item;
}
};
Functor functor();
std::for_each(collection.begin(), collection.end(), functor);
Objective-C
for(id item in collection) {
NSLog(item);
}
Swift
for item in collection {
print(item)
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
Kotlin
for (item in collection) {
print(item)
}
Java
for (Object item : collection) {
System.out.println(item);
}
C#
foreach (object item in collection) {
System.Console.WriteLine(item);
}
Dart
TypeScript
JavaScript
for (item of collection) {
console.log(item);
}
for (item in collection) {
if (collection.hasOwnProperty(item)) {
console.log(item);
}
}
ActionScript
for each (var item in collection) {
trace(item);
}
for (item in collection) {
trace(collection[item]);
}
// TODO check if behavior
// is similar to JavaScript
var collection:Array = ['p', 'r', 'e'];
// or
var collection:Vector.<Object> = new Vector.<Object>['p', 'r', 'e'];
collection.forEach(function callback(item:*, index:int, arr:Array):void {
trace(item.prop);
// or
trace(arr[index]);
});
Python
collection =
for n in collection:
#
PHP
VBA / VB6
For Each item In collection
Print item
Next
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Rust
for index in 0..5 {
println!("{}", x); // x: i32
}
Go
// usar range + uma coleção
// não possui um operador ..
C++
// c++ 20+
Objective-C
-Swift
for index in 0...4 {
print("\(index) times 5 is \(index * 5)")
}
let minutes = 30
for tickMark in 0..<minutes {
// render the tick mark each minute (30 times)
}
// range exclusivo - to
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10 ... 25)
}
// range inclusivo - through
let minuteInterval = 5
for tickMark in stride(from: 0, through: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10 ... 30)
}
Kotlin
for (i in 0..4) {
print(i)
}
Java
-C#
-Dart
TypeScript
JavaScript
-ActionScript
-Python
for n in range(0, 4, 1):
#
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
for (var i:int = 0; i < 3; i++) {
//
}
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
// label e break / continue
'loop1: for i in 0...3 {
'loop2: for j in 0...3 {
if (i == 1 && j == 1) {
continue 'loop1; // pode usar break tb
}
println!(
"i = {0}, j = {1}",
i, // 0
j // 1
)
}
}
// switch e match
match x {
1 | 2 => println!("one or two"),
3...5 => println!("between three and five"),
6 => println!("six"),
// default é opcional, mas se ausente
// os demais cases devem ser exaustivos
_ => println!("something else"),
}
// ver destructuring
Go
Outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
//
continue Outer
}
}
switch 1 {
case 1:
fmt.Println(1)
fallthrough
case 2:
fmt.Println(2)
}
C++
// TODO testar isso
// label e goto
for (int a = 0; a < 10; ++a) {
for (int y = 0; y < 10; ++y) { // Run until condition.
for (int x = 0; x < 10; ++x) { // Run until condition.
if (x == 5 && y == 5) {
goto Outer;
}
}
++dummy;
}
Outer:
continue;
}
return dummy;
switch(color) {
case GREEN:
case RED:
case BLUE:
Paint();
break;
case YELLOW:
if(AlsoHasCriteriaX) {
Paint();
break; /* notice break here */
}
goto explicit_label;
case FUCHSIA:
PokeEyesOut();
break;
default:
explicit_label:
Print("Ugly color, no paint.")
break;
}
Objective-C
Swift
// label e break / continue
loop1:
for i in 0..<3 {
loop2:
for j in 0..<3 {
if (i == 1 && j == 1) {
continue loop1; // pode usar break tb
}
print("i = \(i), j = \(j)")
}
}
// testar isso
/*label: {
// do stuff
if check break label
// do more stuff
}*/
// switch e fallthrough
switch a {
case "a":
// tem que ser indicado explicitamente
// com a palavra fallthrough
fallthrough
case "A":
//
default:
//
}
// switch e match
switch a {
case "a", "A":
print("The letter A")
// break é implícito
// mas ainda pode ser usado
// no meio de um bloco por exemplo
// default é opcional, mas se ausente
// os demais cases devem ser exaustivos
default:
print("Not the letter A")
}
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
default:
naturalCount = "many"
}
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
Kotlin
// label e break / continue
loop1@
for (i in 0 until 3) {
loop2@
for (j in 0 until 3) {
if (i == 1 && j == 1) {
continue@loop1 // pode usar break@ tb
}
println("i = $i, j = $j")
}
}
// testar isso
/*label: {
// do stuff
if (check) break label
// do more stuff
}*/
// switch e match (em kotlin se chama when)
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Java
// label e break / continue
loop1:
for (...) {
loop2:
for (...) {
continue loop1; // pode usar break tb
}
}
label: {
// do stuff
if (check) break label;
// do more stuff
}
// switch e "match" - java 12+
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
// switch expressions - java 14+
var title = switch (person) {
case Dali, Picasso -> "painter";
case Mozart, Prokofiev -> "composer";
case Goethe, Dostoevsky -> "writer";
};
// match - java 17+
switch (o) {
case null -> System.out.println("null");
case String s -> System.out.println("String");
case Color c -> System.out.println("Color with " + Color.values().length + " values");
case Point p -> System.out.println("Record class: " + p.toString());
case int[] ia -> System.out.println("Array of ints of length" + ia.length);
default -> System.out.println("Something else");
}
C#
// label e goto
for (int a = 0; a < 10; a++) {
for (int y = 0; y < 10; y++) { // Run until condition.
for (int x = 0; x < 10; x++) { // Run until condition.
if (x == 5 && y == 5) {
goto Outer;
}
}
dummy++;
}
Outer:
continue;
}
return dummy;
// switch e goto
switch (id) {
case 1000:
price += 10;
goto case 100;
case 100:
return price * 10;
default:
return price;
}
// switch fallthrough
switch (id) {
case "ab":
case "cd":
case "ef":
// não pode haver nenhum código entre os "case"
break;
case "gh":
break;
default: // default é opcional
break;
}
// switch e "match" - requer C# 7+
switch(shape) {
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("unknown shape");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
// switch expressions - requer C# 8+
var switchValue = id switch
{
"ab" => 1,
"cd" => 2,
_ => 0
};
Dart
TypeScript
JavaScript
// label e break / continue
loop1:
for (i = 0; i < 3; i++) {
loop2:
for (j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
continue loop1; // pode usar break tb
}
console.log(`i = ${i}, j = ${j}`);
}
}
label: {
// do stuff
if (check) break label;
// do more stuff
}
// switch fallthrough
switch (id) {
case "ab":
case "cd":
// algum código aqui
case "ef":
// não pode haver nenhum código entre os "case"
break;
case "gh":
break;
default: // default é opcional
break;
}
ActionScript
Python
PHP
VBA / VB6
'label e goto, resume e next
On Error GoTo Erro
' Faça alguma coisa e saia da função
' antes de chegar nas linhas de tratamento de erro
Exit Sub
' Label de erro
' Labels não podem conter espaços em branco antes dos nomes
Erro:
' Faça alguma coisa e saia da função
Exit Sub
' Ou continue a execução normalmente
Resume Next
' Ou passe para um tratamento específico
If Err.Number = 13 Then
Resume ErroEspecifico
ErroEspecifico:
Exit Sub
'switch ("select")
Select Case age
Case 50
ageBlock = "the big five-oh"
Case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89
ageBlock = "octogenarian"
Case 90 To 99
ageBlock = "nonagenarian"
Case Is >= 100
ageBlock = "centenarian"
Case Else
ageBlock = "just old"
End Select
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
Assembly
Rust
// declaração de função
fn normal() { /**/ } // mesmo que -> ()
fn normalUnit() -> () { /**/ }
// expressão de função
let expressao = normal;
fn retorno() -> &'static str {
"retorno" // sem ; no final
}
fn retorno() -> &'static str {
return "retorno";
}
use std::any::Any;
fn retorno_misturado(numero:i32) -> Option<Box<dyn Any>> {
if numero > 0 {
return Some(Box::new("string"))
}
Some(Box::new(25))
}
fn superior<F>(funcao:F) where F:fn() {
funcao();
}
fn superior<F>(funcao:F) -> &'static str where F:fn() {
funcao();
}
// TODO fazer superior com type aliasing
superior(normal);
superior(normalUnit);
superior(retorno);
Go
// declaração de função
func normal() { /**/ }
// expressão de função
var expressaoInline = func() { /**/ }
var expressao = normal
func retorno() string { return "retorno" }
func retornoMultiplo() (string, string) {
return "retorno", "multiplo"
}
func retornoMisturado(numero int) interface{} {
if numero > 0 {
return "texto"
}
return 25
}
func retornoNomeado() (nome string) {
nome = "Zé" // declarado pelo nome do retorno
return nome
}
func superior(funcao func()) {
funcao()
}
func superiorRetorno(funcao func() string) {
funcao()
}
superior(normal)
superiorRetorno(retorno)
C++
// declaração de função
void normal() { /**/ }
// expressão de função
auto expressao = normal;
std::string retorno() {
return "retorno";
}
void superior(void(*funcao)()) {
funcao();
}
void superior(std::string(*funcao)()) {
funcao();
}
// ou
using Function_t = void();
void superior(Function_t* funcao) {
funcao();
}
using Function2_t = std::string();
void superior(Function2_t* funcao) {
funcao();
}
// ou
using FunctionPointer = void(*)();
void superior(FunctionPointer funcao) {
funcao();
}
using FunctionPointer2 = std::string(*)();
void superior(FunctionPointer2 funcao) {
funcao();
}
// ou
#include <type_traits>
using FunctionPointer = std::add_pointer<void()>::type;
void superior(FunctionPointer funcao) {
funcao();
}
using FunctionPointer2 = std::add_pointer<std::string()>::type;
void superior(FunctionPointer2 funcao) {
funcao();
}
superior(&normal);
superior(&retorno);
Objective-C
// declaração de função
void normal() { /**/ }
// TODO
Swift
// declaração de função
func normal() { /**/ } // mesmo que -> Void ou -> ()
func normalVoid() -> Void { /**/ }
func normalEmptyTuple() -> () { /**/ }
// expressão de função
let expressao = normal;
func retorno() -> String {
return "retorno"
}
func retornoMisturado(numero:Int) -> Any {
if numero > 0 {
return "texto";
}
return 25;
}
func superior(funcao:() -> Void) {
funcao()
}
func superior(funcao:() -> String) {
funcao()
}
// TODO fazer superior com type aliasing
// TODO explicar nomes de parâmetros
superior(normal)
superior(normalVoid)
superior(normalEmptyTuple)
superior(retorno)
Kotlin
fun runTransformation(f: (String, Int) -> String): String {
return f("hello", 3)
}
Java
-C#
-Dart
TypeScript
JavaScript
// declaração de função
function comum() { /**/ }
function normal(texto) { /**/ }
// expressão de função
const surpresa = function() { /**/ };
const outraSurpresa = normal;
// expressão de função anônima auto executável
// note os () em volta dela
(function() {
//
})();
function retorno() {
return 'retorno';
}
function retornoMisturado(numero) {
if (numero > 0) {
return 'texto';
}
return 25;
}
function superior(funcao) {
funcao();
}
// chamadas perfeitamente válidas
comum(); // arguments será []
comum('lala'); // arguments será ['lala']
comum('lala', 'lolo'); // arguments será ['lala', 'lolo']
normal('lolo'); // texto será 'lolo' e arguments será ['lolo']
// chamada válida
normal(); // o parâmetro texto terá o valor undefined e arguments será []
normal.call(this, 'dadaísmo'); // o parâmetro texto terá o valor 'dadaísmo' e arguments será ['dadaísmo']
ActionScript
Python
# declaração de função
def normal():
pass
def normal(texto):
pass
# expressão de função?
# TODO
def retorno():
return 'retorno'
def retornoMisturado(numero):
if (numero > 0):
return 'texto'
else:
return 25
def superior(funcao):
funcao()
superior(normal)
superior(retorno)
PHP
VBA / VB6
'Métodos que não retornam valores são chamados subrotinas, ou simplesmente subs
Public Sub SemRetorno()
'...
End Sub
'Podemos sair precocemente de um sub usando Exit Sub
Public Sub AbortarCedo()
Dim algumaFlag As Boolean: algumaFlag = True
If algumaFlag Then
Exit Sub 'Equivalente à "return"
End If
'Fazer o resto se passar pela flag
End Sub
'Métodos com retorno são Funções
Public Function ComRetorno() As Boolean
'Equivalente à "return true".
'Note que são necessárias duas linhas
ComRetorno = True 'Esta atribui o valor de retorno, mas não interfere na execução das linhas seguintes
Exit Function 'E esta retorna o valor especificado imediatamente
End Function 'Caso o Exit Function não tenha sido usado, retorna o valor especificado quando chegar aqui
'Tanto subs quanto funções podem receber parâmetros
Private Sub ComParametro(i As Byte)
Exit Sub
End Sub
Private Function ComParametroERetorno(i As Integer) As Boolean
If i <> 0 Then 'Operador diferente é <>
ComParametroERetorno = True
Exit Function
Else
ComParametroERetorno = False
Exit Function
End If
End Function
'Ou
Private Function ComParametroERetorno(i As Integer) As Boolean
ComParametroERetorno = IIf(i <> 0, True, False) 'Inline If (IIf) funciona quase como operador ternário ? :
Exit Function
End Function
'Podemos passar vários parâmetros separando por vírgula
Private Sub ComParametro(i As Long, j As Currency)
'...
End Sub
'E podemos quebrar os parâmetros em até 24 linhas utilizando _ (continuação de linha)
'Note que é necessário um espaço antes de _
'E não podem haver comentários :(
Private Sub ComParametro( _
i As Single, _
j As Double _
)
'Single é float, e Double é double mesmo
End Sub
'Para chamar subrotinas e funções, existem casos em que deve ser usados parênteses, e casos em que eles não devem ser usados
'O uso de parênteses quando não obrigatório faz com que os parâmetros sejam passados por valor ao invés de referência
'Teoricamente Call deveria permitir usar parênteses sempre, mas não é o caso. Não há necessidade de usar Call
'TODO Testar isso aqui
Dim param As Integer: param = 1
Dim param2 As Integer: param = 1
ComRetorno
Call ComRetorno
retorno = ComRetorno
retorno = ComRetorno()
ComParametro param 'Passado por referência
ComParametro(param) 'Passado por valor
Call ComParametro(param)
ComParametroERetorno param 'Passado por referência
ComParametroERetorno(param) 'Passado por valor
Call ComParametroERetorno(param)
retorno = ComParametroERetorno(param)
ComDoisParametros param, param2 'Passado por referência
ComDoisParametros(param, param2) 'Passado por valor
Call ComDoisParametros(param, param2)
ComParametroERetorno param, param2 'Passado por referência
ComParametroERetorno(param, param2) 'Passado por valor
Call ComParametroERetorno(param, param2)
retorno = ComParametroERetorno(param, param2)
Ada
Object Pascal (Delphi)
Ruby
def normal()
#
end
alias semExpressao normal
def retorno()
return 'retorno'
end
def retornoMisturado(numero)
if numero > 0
return 'texto'
end
return 25
end
def superior
yield
end
normal()
retorno()
retornoMisturado(-1)
retornoMisturado(1)
superior &method(:normal)
superior &method(:retorno)
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
LLVM IR
define void @normal() {
ret void;
}
Assembly
A
Rust
// ver ponteiros
Go
// ver ponteiros
C++
// ver ponteiros
Objective-C
// ver ponteiros
Swift
// tipos primitivos por valor por padrão
// modificáveis com inout
// arrays e objetos por referência
func swapTwoInts(_ a:inout Int, _ b:inout Int) {
let temp = a
a = b
b = temp
}
var a = 2
var b = 3
// requer & na frente do nome
// além do inout da definição
swapTwoInts(&a, &b)
Kotlin
// tipos primitivos por valor
// arrays e objetos por referência
Java
// tipos primitivos por valor
// arrays e objetos por referência
C#
// tipos primitivos por valor por padrão
// modificáveis com ref ou out
// arrays e objetos por referência
public void SwapTwoInts(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}
public bool OutExample(string a, out int c) {
// TODO alguma lógica condicional com a
return false;
}
// argumentos ref precisam ser inicializados
// antes de serem passados para a função
var a = 2;
var b = 3;
SwapTwoInts(a, b);
// argumentos out NÃO precisam ser inicializados
// antes de serem passados para a função
int c;
if (!OutExample(c)) {
return;
}
Dart
TypeScript
JavaScript
// tipos primitivos por valor
// arrays e objetos por referência
ActionScript
Python
PHP
VBA / VB6
'O padrão é passar tudo por referência,
'inclusive tipos primitivos como Ints
'Podemos forçar a passagem de um parâmetro
'por valor ou por referência usando ByVal e ByRef
'Essa palavras não tem efeito quando passamos constantes
'Arrays e User Defined Types (UDTs) não podem
'ser passados por valor
Private Sub PorValor(ByVal i As Long)
'...
End Sub
Private Sub PorReferencia(ByRef i As Long)
'...
End Sub
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Rust
-Go
-C++
void point(int x, int y) { /**/ }
void point(int x, int y = 4) { /**/ }
void point(int x = 3, int y = 4) { /**/ }
Objective-C
-Swift
//func point(x:Int, y:Int) { /**/ } // testar
func point(x:Int, y:Int = 4) { /**/ }
// func point(x:Int = 3, y:Int = 4) { /**/ } //testar
Kotlin
// fun point(x:Int, y:Int) { /**/ } // testar
fun point(x:Int, y:Int = 4) { /**/ }
// fun point(x:Int = 3, y:Int = 4) { /**/ } // testar
// named arguments
fun point(x:Int = 3, y:Int) { /**/ }
// também overload como alternativa
Java
// não possui
// usar overload como alternativa
C#
// public void Point(int x, int y) { /**/ } // testar
public void Point(int x, int y = 4) { /**/ }
// public void Point(int x = 3, int y = 4) { /**/ } // testar
// também overload como alternativa
Dart
TypeScript
JavaScript
// a assinatura das funções não é verificada ao chamá-las
// podemos passar mais ou menos argumentos para a função
// independente de como ela foi definida
// os argumentos a mais não terão nome
// e os argumentos a menos terão o valor null
function point(x, y) {
if (y == null) {
y = 4;
}
}
ActionScript
Python
def point(x, y = 4):
#
PHP
VBA / VB6
Private Sub Point(X As Integer, Optional Y As Integer = 4)
'
End Sub
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Rust
// usar builder pattern
// como alternativa
Go
// usar builder pattern
// como alternativa
C++
// usar builder pattern
// como alternativa
Objective-C
// todos os argumentos devem ser nomeados
Swift
func namedArgs(
tooMany:Int,
args:Int,
toRemember:Bool,
theirMeaning:String = "a",
byPosition:String = "b"
) {
//
}
// argumentos devem seguir a ordem
// mas os que possuem valor padrão
// podem ser omitidos
namedArgs(
tooMany: 2,
args: 1,
toRemember: false,
byPosition: "args"
)
// nomes dos argumentos que podem
// ser omitidos devem usar _ para
// o nome externo
func unnamedArgs(
tooMany:Int,
_ args:Int,
_ toRemember:Bool,
_ theirMeaning:String = "a",
_ byPosition:String = "b"
) {
//
}
unnamedArgs(tooMany: 2, 1, false, "args")
Kotlin
fun namedArgs(
tooMany:Int,
args:Int,
toRemember:Boolean,
theirMeaning:String = "a",
byPosition:String = "b"
) {
//
}
namedArgs(
tooMany = 2,
args = 1,
toRemember = false,
byPosition = "args"
)
// TODO verificar isso pq tem parâmetro faltando
namedArgs(
2,
args = 1,
toRemember = false,
byPosition = "args"
)
// TODO verificar isso pq tem parâmetro faltando
namedArgs(tooMany = 2, 1, false, "args")
Java
// usar builder pattern
// como alternativa
C#
public class NamedArgs {
public NamedArgs(
int tooMany,
int args,
bool toRemember,
string theirMeaning = "a",
string byPosition = "b"
) {
//
}
}
// argumentos não precisam seguir a ordem
// e os que possuem valor padrão podem
// ser omitidos
var ex = new NamedArgs(
args: 1,
toRemember: false,
tooMany: 2,
theirMeaning: "named",
byPosition: "arg"
);
Dart
TypeScript
JavaScript
// usar builder pattern
// como alternativa
ActionScript
Python
def named_args(tooMany, args, toRemember, theirMeaning = 'a', byPosition = 'b'):
#
# TODO mais testes
named_args(tooMany = 2, args = 1, toRemember = false)
PHP
VBA / VB6
'usar builder pattern
'como alternativa
Ada
Object Pascal (Delphi)
Ruby
def named_args(
tooMany:,
args:,
toRemember:,
theirMeaning: 'a',
byPosition: 'b'
)
#
end
named_args(
tooMany: 2,
args: 1,
toRemember: false
)
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Rust
Go
-C++
Objective-C
-Swift
-Kotlin
Java
C#
Dart
TypeScript
JavaScript
-ActionScript
Python
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Rust
// argumentos do mesmo tipo
// usa macros para argumentos variádicos O_O'
macro_rules! imprimirSimples {
($titulo:expr, $($pagina:expr), +) => {{
// na "assinatura" do macro não dá pra diferenciar os tipos
// mas o corpo vai lançar exceção na linha quando compilar
// se o tipo não for &str
let titulo:&str = $titulo;
$(
// poderíamos fazer a verificação dos tipos aqui tb
// se necessário
let pagina = $pagina;
println!("Imprimindo página {}", pagina);
)+
}};
}
imprimirSimples!("resumo", 1, 2, 5);
Rust
// argumentos de todos os tipos
// TODO
Go
// argumentos do mesmo tipo
func imprimirSimples(titulo string, paginas ...int) {
for _, pagina := range paginas {
fmt.Printf("Imprimindo página %v)\n", pagina)
}
}
imprimirSimples("resumo", 1, 2, 5)
Go
// argumentos de todos os tipos
func imprimir(titulo string, paginas ...interface{}) {
for _, pagina := range paginas {
switch value := pagina.(type) {
case string:
fmt.Println("A string")
fmt.Println("Imprimindo página ", value)
case int32:
fmt.Println("An integer")
fmt.Println("Imprimindo página ", value)
case []int32:
fmt.Println("A slice")
fmt.Println("Imprimindo páginas ", value)
default:
fmt.Println("A default")
}
}
}
pageSlice := make([]int32, 3)
imprimir("resumo", 1, pageSlice, "capítulo 2")
C++
// argumentos do mesmo tipo
#include <iostream>
using std::string;
using std::cout;
using std::endl;
template<typename... Tipos>
void imprimirSimples(string titulo, Tipos... paginas) {
const uint16_t quantidadeDeParametros {sizeof...(paginas)};
// não pode criar uma array com 0 elementos
if (quantidadeDeParametros == 0) {
return;
}
// expande os argumentos
int paginasArray[quantidadeDeParametros] {paginas...};
for (auto pagina : paginasArray) {
cout << "Imprimindo página " << pagina << endl;
}
}
imprimirSimples("resumo", 1, 2, 5);
C++
// argumentos de todos os tipos
#include <iostream>
#include <boost/range/irange.hpp>
using std::string;
using std::cout;
using std::endl;
/// imprimirHelper template genérico
template<typename T>
void imprimirHelper(T pagina) {
// poderia usar a linha abaixo para descobrir o tipo de T
// porém, melhor usar o template especializado
// if (std::is_same<T, int>::value) { /* ... */ }
cout << "Imprimindo outra coisa" << endl;
}
/// imprimirHelper template especializado para int
template<>
void imprimirHelper<int>(int pagina) {
cout << "Imprimindo página " << pagina << endl;
}
/// imprimirHelper template especializado para boost::irange
template<>
void imprimirHelper<boost::irange>(boost::irange faixa) {
cout << "Imprimindo página " << std::begin(faixa) << " até " << std::end(faixa) << endl;
}
// foward declaration imprimir template?? Não estou certo da função disso :/
void imprimir(string titulo) {}
// implementação imprimir template
template<typename Tipo, typename... Tipos>
void imprimir(string titulo, Tipo pagina, Tipos... paginas) {
// executa o helper especializado e chama recursivamente a si mesmo
imprimirHelper(pagina);
imprimir(titulo, paginas...);
}
imprimir<int, boost::irange, string>("resumo", 1, boost::irange(2, 5), "capítulo 2");
Objective-C
// macros não seguras estilo C
#include <iostream>
#include <cstdarg>
void imprimirSimplesMacro(const std::string titulo, ...) {
// va_list argumentos recebe o que vir depois do parâmetro titulo
va_list argumentos;
va_start(argumentos, titulo);
int pagina;
while (true) {
pagina = va_arg(argumentos, int);
if (pagina == -1) {
break;
}
std::cout << "Imprimindo " << pagina << std::endl;
}
va_end(argumentos);
}
// preciso sempre passar -1 no final como terminador
// se não dá overflow e lê pedaço de memória além do que deveria
imprimirSimplesMacro("resumo", 1, 2, 5, -1);
Swift
// argumentos do mesmo tipo
func imprimirSimples(titulo titulo:String, paginas:Int...) {
for pagina in paginas {
print("Imprimindo página \(pagina) num total de \(paginas.count)")
}
}
imprimirSimples(titulo: "resumo", paginas: 1, 2, 5)
Swift
// argumentos de todos os tipos
func imprimir(titulo titulo:String, paginas:Any...) {
for valor in paginas {
switch valor {
case let pagina as Int:
print("Imprimindo página \(pagina)")
case let faixa as Range<Int>:
print("Imprimindo páginas \(faixa.first!) até \(faixa.last!)")
default:
print("Imprimindo outra coisa")
}
}
}
imprimir(titulo: "resumo", paginas: 1, 2...5, "capítulo 2")
Kotlin
// argumentos do mesmo tipo
imprimirSimples(titulo:String, vararg paginas:Int) {
/*for (int pagina : paginas) {
System.out.println(String.format("Imprimindo página %1", pagina));
}*/
}
imprimirSimples("resumo", 1, 2, 5);
Kotlin
// argumentos de todos os tipos
/*void imprimir(titulo:String, Object... paginas) {
for (Object valor : paginas) {
if (valor instanceof Integer) {
System.out.println(String.format("Imprimindo página %d", valor));
} else if (valor instanceof Range<Integer>) {
System.out.println(String.format(
"Imprimindo páginas %d até %d",
((Range<Integer>)valor).getMinimum(),
((Range<Integer>)valor).getMaximum()
));
} else {
System.out.println("Imprimindo outra coisa");
}
}
}
imprimir("resumo", 1, Range.between(2, 5), "capítulo 2");*/
Java
// argumentos do mesmo tipo
void imprimirSimples(String titulo, int... paginas) {
for (int pagina : paginas) {
System.out.println(String.format("Imprimindo página %1", pagina));
}
}
imprimirSimples("resumo", 1, 2, 5);
Java
// argumentos de todos os tipos
void imprimir(String titulo, Object... paginas) {
for (Object valor : paginas) {
if (valor instanceof Integer) {
System.out.println(String.format("Imprimindo página %d", valor));
} else if (valor instanceof Range<Integer>) {
System.out.println(String.format(
"Imprimindo páginas %d até %d",
((Range<Integer>)valor).getMinimum(),
((Range<Integer>)valor).getMaximum()
));
} else {
System.out.println("Imprimindo outra coisa");
}
}
}
imprimir("resumo", 1, Range.between(2, 5), "capítulo 2");
C#
// argumentos do mesmo tipo
void ImprimirSimples(string titulo, params int[] paginas) {
foreach (int pagina in paginas) {
System.Console.WriteLine(
@"Imprimindo pagina {0} num total de {1}",
pagina,
paginas.Length
);
}
}
ImprimirSimples(@"resumo", 1, 2, 5);
C#
// argumentos de todos os tipos
void Imprimir(string titulo, params object[] paginas) {
foreach (object valor in paginas) {
if (valor is int) {
System.Console.WriteLine(@"Imprimindo página {0}", valor);
} else if (valor is IEnumerable<int>) {
System.Console.WriteLine(
@"Imprimindo páginas {0} até {1}",
(valor as IEnumerable<int>).First(),
(valor as IEnumerable<int>).Last()
);
} else {
System.Console.WriteLine(@"Imprimindo outra coisa");
}
}
}
Imprimir(@"resumo", 1, Enumerable.Range(2, 4), @"capítulo 2");
Dart
TypeScript
JavaScript
'use strict';
// argumentos do mesmo tipo
function imprimirSimples(titulo, ...paginas) {
for (let pagina of paginas) {
console.log(`Imprimindo página ${pagina}`);
}
}
imprimirSimples("resumo", 1, 2, 5);
JavaScript
'use strict';
// argumentos de todos os tipos
function imprimir(titulo, ...paginas) {
for (let valor of paginas) {
if (Number.isInteger(valor)) {
console.log(`Imprimindo página ${valor}`);
} else if ((valor.begin || valor.begin === 0)
&& valor.end
) {
console.log(`Imprimindo páginas ${valor.begin} até ${valor.end}`);
} else {
console.log('Imprimindo outra coisa');
}
}
}
imprimir("resumo", 1, {begin: 2, end: 5}, "capítulo 2");
ActionScript
Python
# argumentos do mesmo tipo
def imprimirSimples(titulo, *paginas):
for pagina in paginas:
print("Imprimindo página " + pagina)
imprimirSimples()
Python
# argumentos de todos os tipos
def imprimir(titulo, *paginas):
for valor in paginas:
# TODO
imprimir()
PHP
VBA / VB6
' argumentos do mesmo tipo
Public Sub ImprimirSimples(titulo As String, ParamArray paginas() As Integer)
Dim pagina As Integer
For Each pagina In paginas
Print pagina
Next
End Sub
Imprimir "resumo", 1, 2, 5
Ada
Object Pascal (Delphi)
Ruby
# argumentos do mesmo tipo
def imprimirSimples(titulo, *paginas)
for pagina in paginas
puts "Imprimindo página #{pagina}"
end
end
imprimirSimples("resumo", 1, 2, 5);
Ruby
# argumentos de todos os tipos
def imprimir(titulo, *paginas)
for valor in paginas
if valor.is_a? Numeric
puts "Imprimindo página #{valor}"
elsif (defined?(valor.begin) || (defined?(valor.begin) && valor.begin === 0)) && defined?(valor.end)
puts "Imprimindo páginas #{valor.begin} até #{valor.end}"
else
puts "Imprimindo outra coisa"
end
end
end
imprimir("resumo", 1, 2..5, "capítulo 2")
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
fn main() {
// Increment via closures and functions.
fn function(i:i32) -> i32 { i + 1 }
// Closures are anonymous, here we are binding them to references
// Annotation is identical to function annotation but is optional
// as are the `{}` wrapping the body. These nameless functions
// are assigned to appropriately named variables.
let closure_annotated = |i:i32| -> i32 { i + 1 };
let closure_inferred = |i | i + 1 ;
let i = 1;
// Call the function and closures.
println!("function: {}", function(i));
println!("closure_annotated: {}", closure_annotated(i));
println!("closure_inferred: {}", closure_inferred(i));
// A closure taking no arguments which returns an `i32`.
// The return type is inferred.
let one = || 1;
println!("closure returning one: {}", one());
}
Go
// suporta funções anônimas e closures
// mas não lambda com arrow syntax ou algo parecido
func superiorRetorno(funcao func(x int) int) {
fmt.Println(funcao(1))
}
superiorRetorno(func(x) { return x + 1 })
C++
Objective-C
Swift
func superior(funcao:() -> Void) {
funcao()
}
// declaração simplificada
superior({() in print("lambda")})
func superior(funcao:(_:Int) -> Int) {
print(funcao(1))
}
// declaração simplificada
superior({x in x + 1})
// declaração completa
superior({(x:Int) -> Int in
return x + 1
})
// superior({x, y in x + y})
Kotlin
val sum:(Int, Int) -> Int = { x:Int, y:Int -> x + y }
// suporta closures tb
Java
public class Main {
public static void main(String[] args) {
// não são funções de verdade, são classes
// que podem ser declaradas como se fossem
// funções lambda, mas ainda é preciso chamar
// o método da classe para executá-las
// no caso do exemplo, o método se chama call
// declaração simplificada
Main.superior(() -> System.out.println("lambda"));
// declaração simplificada
Main.superior(x -> x + 1);
// declaração completa
Main.superior((int x) -> {
return x + 1;
});
// Main.superior(x, y -> x + y);
}
@FunctionalInterface
public interface Lambda {
void call();
}
public static void superior(Lambda funcao) {
funcao.call();
}
@FunctionalInterface
public interface Lambda2 {
int call(int x);
}
public static void superior(Lambda2 funcao) {
System.out.println(funcao.call(1));
}
}
C#
public class Main {
public static void Main(string[] args) {
// declaração simplificada
Main.superior(() => System.Console.WriteLine("lambda"));
// declaração simplificada
Main.superior(x => x + 1);
// declaração completa
Main.superior((int x) => {
return x + 1;
});
// Main.superior(x, y -> x + y);
}
public delegate void LambdaDelegate();
public static void superior(LambdaDelegate funcao) {
funcao();
}
public delegate int Lambda2Delegate(int x);
public static void superior(Lambda2Delegate funcao) {
System.Console.WriteLine(funcao(1));
}
}
Dart
TypeScript
JavaScript
function superior(funcao) {
funcao();
}
// declaração simplificada
superior(() => console.log('lambda'));
// declaração antiga
superior(function() { /**/ });
function superior2(funcao) {
console.log(funcao(1));
}
// declaração simplificada
superior(x => x + 1);
// declaração completa
superior((x) => {
return x + 1;
});
// superior(x, y => x + y)
ActionScript
Python
x = lambda a, b, c : a + b + c
# TODO mover para exemplo de closure
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
PHP
VBA / VB6
' ver exemplo
Ada
Object Pascal (Delphi)
Ruby
def adder(a, b)
lambda { a + b }
end
adder_fn = adder(1, 2)
adder_fn.call
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
fn externa() {
fn interna() { /**/ }
// let internaLambda = || { /**/ };
interna();
internaLambda();
}
Go
func externa() {
func main() {
internaLambda := func() { /**/ }
internaLambda()
}
}
C++
void externa() {
auto internaLambda = [](){ /**/ };
// ou
struct internaFunctor { // testar isso
void operator()() { /**/ }
};
internaLambda();
internaFunctor();
}
Objective-C
// blocks em métodos
Swift
func externa() {
func interna() { /**/ }
// let internaLambda = {() in /**/ }
interna()
internaLambda();
}
Kotlin
Java
public class Main {
public static void main(String[] args) {
// não são funções de verdade
// ver lambdas acima para explicação
Funcional interna = () -> {
System.out.println("interna");
};
interna.call();
Funcional2 interna2 = x -> x + 1;
int y = interna2.call(1);
}
@FunctionalInterface
public interface Funcional {
void call();
}
@FunctionalInterface
public interface Funcional2 {
int call(int x);
}
}
C#
public class Main {
public static void Main(string[] args) {
InternaDelegate interna = () => {
System.Console.WriteLine(@"interna");
};
interna();
Interna2Delegate interna2 = x => x + 1;
var y = interna2(1);
// ou
Action interna = new Action(() => {
System.Console.WriteLine(@"interna");
})); // testar isso
Func<int> interna2 = new Func<int>(x => x + 1);
// C# 7 deverá permitir funções locais também
}
delegate void InternaDelegate();
delegate int Interna2Delegate(int x);
}
Dart
TypeScript
JavaScript
function externa() {
function interna() { /**/ }
let internaLambda = () => { /**/ };
interna();
internaLambda();
}
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Swift, Rust e JavaScript permitem a criacão natural de funções dentro de funções.
C++ requer o uso de um lambda, mas seu tipo pode ser deduzido pelo compilador.
C# também usa um lambda, mas seu tipo deve ser declarado por meio de um delegate
.
Java não possui funções internas de verdade. São classes com uma sintaxe um pouco mais reduzida.
Objective-C?
Rust
Go
package main
import "fmt"
func facade() func() int {
// acessível somente pela função interna
i := 0
interna := func() int {
i++
return i
}
// expõe a função interna
return interna
}
func main() {
closure := facade()
fmt.Println(closure()) // 1
fmt.Println(closure()) // 2
}
C++
#include <iostream>
int main(int argc, const char* argv[]) {
using std::make_shared;
using std::cout;
using std::endl;
auto facade = [](){
// acessível somente pela função interna
auto i = make_shared<int>();
auto interna = [i](){
(*i)++;
return *i;
};
// expõe a função interna
return interna;
};
auto closure = facade();
cout << closure() << endl; // 1
cout << closure() << endl; // 2
return 0;
}
Objective-C
#import <Foundation/Foundation.h>
int main(int argc, const char* argv[]) {
// typedef ajuda na legibilidade
typedef int (^interna_t)(void);
typedef interna_t (^facade_t)(void);
facade_t facade = ^{
// acessível somente pela função interna
__block int i = 0;
interna_t interna = ^{
i++;
return i;
};
// expõe a função interna
return interna;
};
interna_t closure = facade();
NSLog(@"%i", closure()); // 1
NSLog(@"%i", closure()); // 2
return 0;
}
Swift
func facade() -> () -> Int {
// acessível somente pela função interna
var i = 0
func interna() -> Int {
i = i + 1
return i
}
// expõe a função interna
return interna
}
let closure = facade();
print(closure()); // 1
print(closure()); // 2
Kotlin
Java
class ClosureState {
public int i;
}
public class MainClosure {
@FunctionalInterface
public interface Interna {
int call();
}
static Interna facade() {
// acessível somente pela "função" interna
final ClosureState closureState = new ClosureState();
Interna interna = () -> {
closureState.i++;
return closureState.i;
};
// expõe a "função" interna
return interna;
}
public static void main(String[] args) {
Interna closure = facade();
System.out.println(closure.call()); // 1
System.out.println(closure.call()); // 2
}
}
// PS: pra evitar ter que declarar uma classe ClosureState
// eu poderia ter feito
final Object closureState = new Object() {
public int i;
};
// mas aí para ler as propriedades eu teria que usar
// reflection toda a vez
Class ClosureClass = closureState.getClass();
Field IField = ClosureClass.getDeclaredField("i")
IField.getInteger(closureState);
C#
public class MainClassClosure {
delegate int InternaDelegate();
static InternaDelegate Facade() {
// acessível somente pela função interna
int i = 0;
InternaDelegate interna = () => {
i++;
return i;
};
// expõe a função interna
return interna;
}
public static void Main(string[] args) {
var closure = Facade();
System.Console.WriteLine(closure()); // 1
System.Console.WriteLine(closure()); // 2
}
}
Dart
TypeScript
JavaScript
'use strict';
function facade() {
// acessível somente pela função interna
let i = 0;
let interna = () => {
i++;
return i;
};
// expõe a função interna
return interna;
}
let closure = facade();
console.log(closure()); // 1
console.log(closure()); // 2
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Swift e JavaScript são os mais sucintos. É verdade que é necessário saber da existência de closures para não criar uma sem querer, como muitos programadores JavaScript devem ter descoberto da pior maneira. Porém as novas regras de escopo, similares às das demais linguagens minimizam esse problema.
Rust?
Em comparação com as linguagens anteriores, C# requer apenas a declaração de um delegate
a mais.
C++ por sua vez, requer cuidados no gerenciamento de memória das variáveis acessadas pela closure com make_shared
.
Java complica um pouco o padrão, requerendo que as variáveis sejam membros de um objeto marcado como final
.
Objective-C possui uma sintaxe bastante difícil para identificar as closures, e o uso de aliases torna as assinaturas um pouco mais legíveis. Também é necessário identificar de maneira especial as variáveis que serão usadas na closure com __block
.
Rust
type StrategySignature = fn(i32, i32) -> i32
//
Go
type StrategySignature func(int, int) int
func AddStrategy(i1 int, i2 int) int {
return i1 + i2
}
func MultiplyStrategy(i1 int, i2 int) int {
return i1 * i2
}
func main() {
var typeCurrentStrategy StrategySignature
var inlineCurrentStrategy func(int, int) int
typeCurrentStrategy = AddStrategy
inlineCurrentStrategy = AddStrategy
typeCurrentStrategy(1, 2) // 3
typeCurrentStrategy(1, 2) // 3
typeCurrentStrategy = MultiplyStrategy
inlineCurrentStrategy = typeCurrentStrategy
typeCurrentStrategy(1, 2) // 2
typeCurrentStrategy(1, 2) // 2
}
C++
Objective-C
Swift
typealias StrategySignature = (Int, Int) -> Int
func addStrategy(_ i1:Int, _ i2:Int) -> Int {
return i1 + i2
}
func multiplyStrategy(_ i1:Int, _ i2:Int) -> Int {
i1 * i2
}
var subtractStrategy = {(i1:Int, i2:Int) -> Int in
i1 - i2
}
var divideStrategy:StrategySignature = { i1, i2 in i1 / i2 }
var otherStrategy:StrategySignature = {$0 + $1}
var typeCurrentStrategy:StrategySignature
var inlineCurrentStrategy:func(Int, Int) -> Int
typeCurrentStrategy = addStrategy
inlineCurrentStrategy = addStrategy
typeCurrentStrategy(1, 2) // 3
typeCurrentStrategy(1, 2) // 3
typeCurrentStrategy = multiplyStrategy
inlineCurrentStrategy = typeCurrentStrategy
typeCurrentStrategy(1, 2) // 2
typeCurrentStrategy(1, 2) // 2
Kotlin
// notice that for signatures
// the return type is separated by -> and not :
// ugh...
typealias StrategySignature = (Int, Int) -> Int
fun addStrategy(i1:Int, i2:Int) :Int {
return i1 + i2
}
val multiplyStrategy = fun(i1:Int, i2:Int) :Int {
i1 * i2
}
val subtractStrategy:StrategySignature = { i1, i2 -> i1 - i2 }
//
Java
C#
delegate int StrategySignature(int, int);
//
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust
mod
Rust
use
Go - moduleRootFolder
# dentro de um diretório
go mod init github.com/path/to/module/repo
# isso vai criar um go.mod
Go - moduleRootFolder/go.mod
module github.com/path/to/module/repo
go 1.15
Go - moduleRootFolder/subfolder/sub.go
package subfolder
// nome do pacote não precisa ser
// o mesmo da pasta, mas é recomendado
func init() {
// executado quando um pacote é importado
}
// nomes começando com maiúsculo
// são visíveis fora do pacote
func ExportedFunc() {
//
}
type ExportedStruct struct {
//
}
// nomes começando com minúsculo
// só são visíveis dentro do próprio pacote
func packagePrivate() {
//
}
Go - moduleRootFolder/othersubfolder/main.go
package main
// import with . in front will remove the need to use
// the full package.struct name, only struct name would do
// import with _ in front for using side-effects only
// (running the init func)
// use o caminho configurado em go.mod + nome do pacote
import (
"github.com/path/to/module/repo/subfolder"
)
// ExportedStruct alias without namespace
type ExportedStruct = sub.ExportedStruct
func main() {
// use o alias criado
exportedStruct := ExportedStruct{}
// ou o nome completo
exportedStruct := sub.ExportedStruct{}
sub.ExportedFunc()
}
C++ 20+ - modulo.cpp
export module marcoluglio;
export class DentroDoModulo;
class DentroDoModulo final {
// ...
};
C++ 20+ - main.cpp
import marcoluglio;
int main() {
auto meuObjeto = DentroDoModulo();
}
C++ - DentroDoModulo.hpp
#ifndef MARCOLUGLIO_DENTRODOMODULO_HPP_INCLUDED
#define MARCOLUGLIO_DENTRODOMODULO_HPP_INCLUDED
namespace marcoluglio {
class DentroDoModulo {};
}
#endif /* MARCOLUGLIO_DENTRODOMODULO_HPP_INCLUDED */
C++ - DentroDoModulo.cpp
#include "DentroDoModulo.hpp"
namespace marcoluglio {
//
}
C++ - main.cpp
#include "DentroDoModulo.hpp"
int main(int argc, const char* argv[]) {
using marcoluglio::DentroDoModulo;
DentroDoModulo meuObjeto = DentroDoModulo();
}
Objective-C - MLGDentroDoModulo.h
#import <Foundation/Foundation.h>
@interface MLGDentroDoModulo : NSObject
//
@end
Objective-C - MLGDentroDoModulo.m
#import "MLGDentroDoModulo.h"
@implementation MLGDentroDoModulo
//
@end
Objective-C - main.m
#import <Foundation/Foundation.h>
#import "MLGDentroDoModulo.h"
int main(int argc, const char* argv[]) {
MLGDentroDoModulo* meuObjeto;
meuObjeto = [[MLGDentroDoModulo alloc] init];
return 0;
// não possui namespaces
// a utilização de prefixos com 3 letras
// ou mais nas classes é a alternativa
// recomendada
}
Swift - DentroDoModulo.swift
// a criação de namespaces é implícita
// para cada módulo
// um módulo é um agrupamento macro, bem
// diferente do que se utiliza nas
// outras linguagens
// ele abrange um target inteiro de
// compilação como um framework,
// uma biblioteca ou um executável
import UIKit
class DentroDoModulo : UIViewController {
}
Swift - main.swift
let meuObjeto = DentroDoModulo()
Kotlin
Java - marcoluglio/DentroDoModulo.java
package marcoluglio;
public class DentroDoModulo { /**/ }
Java - main.java
import marcoluglio.DentroDoModulo;
public class OlaMundo {
public static void main(String[] args) {
DentroDoModulo meuObjeto;
meuObjeto = new DentroDoModulo();
}
}
C# - DentroDoModulo.cs
namespace marcoluglio {
public class DentroDoModulo { /**/ }
}
C# - main.cs
using marcoluglio;
class MainClass {
public static void Main(string[] args) {
DentroDoModulo meuObjeto;
meuObjeto = new DentroDoModulo();
}
}
Dart
TypeScript
JavaScript - DentroDoModulo.js
'use strict';
export default class DentroDoModulo { /**/ }
JavaScript - main.js
'use strict';
import DentroDoModulo from 'DentroDoModulo';
let meuObjeto = new DentroDoModulo();
JavaScript compatibilidade
'use strict';
// AMD
define('dentroDoModulo', () => {
const DentroDoModulo = class DentroDoModulo() { /**/ }
return DentroDoModulo;
});
define(['dentroDoModulo'], (DentroDoModulo) => {
let meuObjeto = new DentroDoModulo();
});
// CommonJS
// TODO
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
C# e Java possuem maior granularidade. A única diferença entre os dois é que o módulo em Java deve ser replicado na estrutura de pastas dos arquivos que contém as classes, ao passo que em C# não. Se você já teve que cavar dentro de mil pastas por classes Java sabe que isso acaba mais atrapalhando do que ajudando. Porém, deve haver certamente quem diga que a liberdade que C# proporciona nesse quesito pode ser mal utilizada e gerar confusão.
JavaScript até a versão ES6, não possuía nenhuma sintaxe especial para definir módulos. Mesmo após a oficialização da especificação, nenhum navegador a implementou até o momento. O que vemos no exemplo é um padrão denominado AMD que é bastante flexível, porém um pouco redundante e propenso a erros.
Rust?
C++ possui passos manuais na definição de módulos. A sintaxe para aninhar namespaces só será melhorada na próxima especificação (c++1z). Oficialmente a forma de garantir que um módulo não seja importado mais de uma vez, e por consequência sobrescrito, é usar os include guards #ifndef
, #define
e #endif
. A diretiva mais amigável #pragma once
não é oficial, embora a maioria dos compiladores reconheça devido à sua popularidade.
Swift tem uma definição tão abrangente de módulos que quase não se pode dizer que ele tenha uma.
Objective-C herda de C?
Rust
// se não especificar é private
// pub para tornar padrão
Go
/*
In Go, an identifier that starts with
a capital letter is exported from the package,
and can be accessed by anyone outside
the package that declares it.
If an identifier starts with a lower case letter,
it can only be accessed from within the package.
If you need members in a type to only be accessed
by members of that type, you then need to place
that type and its member functions in a separate
package, as the only type in that package.
*/
C++
// padrão é??
// public protected private
Objective-C
Swift
/*
padrão é internal
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
extensions podem acessar private
*/
Kotlin
/*
public é padrão
private, protected, internal and public
tem traits? podem acessar private?
*/
Java
// padrão é package private
// que subclasses não conseguem acessar
// public protected private para modificar
C#
/*
public Access is not restricted.
protected Access is limited to the containing class or types derived from the containing class.
internal Access is limited to the current assembly.
protected internal Access is limited to the current assembly or types derived from the containing class.
private Access is limited to the containing type.
private protected Access is limited to the containing class or types derived from the containing class within the current assembly. Available since C# 7.2.
extension methods podem acessar private?
*/
Dart
TypeScript
JavaScript
// export import
// dentro de um módulo tudo é public
// pode documentar com JSDoc
// a visibilidade sugerida
// usar _ como sugestão
// ou closures
ActionScript
Python
# começando com _ é protected
# começando com __ é private
PHP
VBA / VB6
'ver descrição
'Private A classe não pode ser acessada fora do projeto.
'Public Not Creatable Instâncias da classe somente podem ser criadas dentro do projeto que definiu a classe.Outras aplicações , no entanto, podem acessar a classe.
'SingleUse Outras aplicações podem criar instâncias da classe.Porém a cada instância criada inicia uma cópia do programa que contém a classe.
'Global SingleUse A classe atua como uma variável goblal no programa cliente.
'MultiUse Outras aplicações podem criar inúmeras instâncias da classe iniciando somente uma vez o programa que contém a classe. Os projetos ActiveX DLL comportam-se assim.
'Global MultiUse Idêntica a MultiUse mas a classe atua como uma variável goblal no programa cliente.
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
// retorna múltiplos valores com Result<R, E>
fn may_return_error(x:i32) -> Result<i32, &'static str> {
None => Err("Error"), // retorna um erro
Some(0) => Err("0 não permitido"), // retorna um erro
Some(_) => Ok(x),
}
match may_return_error(1) {
Ok(result) => println!("{}", result),
Err(err) => println!("Error: {}", err),
}
// runtime panic + match Ok, Err
fn may_runtime_panic() -> &str {
panic!("Error message"); // gera uma exceção
"Ok"
}
match may_runtime_panic() {
Ok(result) => println!("{}", result),
Err(err) => println!("Error: {}", err),
}
// ou
// pode usar Result ou Option
fn a() -> Result<a, b> { // TODO
let result = may_runtime_panic()?;
Ok(result)
}
// try {} block e ?
// acompanhe essa feature
// e unstable docs
// NÃO COPIE!!! DEPRECATED!!!
// houve uma proposta de usar do catch {},
// mas ela foi substituída pelo try {}
// havia uma sintaxe para try!
// mas ela foi substituída por ?
let result = try!(may_panic()); // 2015-
let result = r#try!(may_panic()); // 2018 legacy
Go
// retorna múltiplos valores
func mayReturnError(fileName string) (content string, err error) {
// defer é mais ou menos um bloco "finally"
// sempre vai executar ao final da função
// em que foi definido
// se você tiver vários defers eles irão
// executar na ordem oposta em que foram
// definidos (first in, last out)
file, err := os.Open(fileName)
defer file.Close()
if err != nil {
return "", err // retorna um erro
}
return file.String(), err
}
// runtime panic + recover
func mayRuntimePanic() {
panic("Error message") // gera uma exceção
}
func f() {
// bloco "catch" como um lambda auto executável
// o que torna ele um catch ao invés de um finally
// é que nós checamos o resultado de recover antes
// de prosseguir
defer func() {
// recover() == nil se nenhum panic ocorreu
if r := recover(); r == nil {
return
}
fmt.Println("Recovered control")
}()
mayRuntimePanic()
}
C++
#include <exception>
using std::exception;
try {
throw anyType; // gera uma exceção
// ou simplesmente
throw; // gera uma exceção
} catch (const exception& ex) {
// roda se jogou uma exceção
} catch (...) {
// roda sempre, independente se uma exceção ocorreu ou não
}
// ou retorna múltiplos valores com expected<R, E>
// C++23 +
#include <expected>
auto mayReturnError(int x) -> std::expected<int, parse_error> {
if (x != 0) {
return x;
} else {
return std::unexpected(parse_error::invalid_input);
}
}
// NÃO COPIE!!! DEPRECATED!!!
// havia uma sintaxe para "checked exceptions"
int podeOuNao(int param) throw();
int podeOuNao(int param) throw(someType);
Objective-C
- (void) someMethod {
@try {
@throw exception; // gera uma exceção
} @catch (NSException *exception) {
// roda se jogou uma exceção
} @finally {
// roda sempre, independente se uma exceção ocorreu ou não
}
}
// ou
someCFunction(); // TODO exception estilo C, com error codes?
Swift
enum MLError : Error {
case Bad
case Worse
case Worst
}
// throws antes do corpo da função indica
// que ela pode gerar uma exceção e
// vai propagá-la ao invés de tratá-la
// cabe a quem executou a função tratar
// a exceção OBRIGATORIAMENTE
// ou indicar que vai propagá-la também
func podeOuNao() throws -> String {
throw MLError.Bad
}
// para outras funções, é esperado que
// a exceção seja tratada dentro dela mesma
func naoPode() -> String {
//
}
// para tratar exceções
// defer é mais ou menos um bloco "finally"
// sempre vai executar ao final da função
// em que foi definido
// se você tiver vários defers eles irão
// executar na ordem oposta em que foram
// definidos (first in, last out)
do {
// abrir resources
defer {
// fechar resources
}
try throw MLError.Bad // gera uma exceção
} catch MLError.Bad {
// roda se jogou uma exceção
} catch MLError.Worse, MLError.Worst {
// roda se jogou uma exceção
}
// ou com try? - nil se jogar exceção
let result = try? podeOuNao() {
// roda se for tudo bem
}
// mesmo que
let result = try? podeOuNao()
guard result != nil else { return }
// ou com try! - gera runtime exception se throws
let result = try! podeOuNao()
// TODO rethrows
Kotlin
try {
throw Exception() // gera uma exceção
} catch (ex:Exception) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
try {
// sem finally
} catch {
// roda se jogou uma exceção
}
try {
// sem catch
} finally {
// roda sempre
}
// ou retorna múltiplos valores com Result<T>
// não é necessário especificar o tipo da exceção
// pois ela sempre herda da classe Throwable
if (x != 0) {
return Result.failure(Exception())
}
return Result.success(x)
Java - Main.java
public class Main {
// throws antes do corpo da função indica
// que ela pode gerar uma exceção e
// vai propagá-la ao invés de tratá-la
// cabe a quem executou a função tratar
// a exceção OBRIGATORIAMENTE
// ou indicar que vai propagá-la também
public static void main(String[] args) throws Exception {
throw new Exception();
}
}
Java - Main.java
// para outras funções, é esperado que
// a exceção seja tratada dentro dela mesma
void main() {
PodeOuNao problematico = new PodeOuNao();
// para tratar exceções
// obrigatório tratar ou indicar que vai propagar
try {
problematico.checkedMethod();
} catch (Exception ex) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
problematico.uncheckedMethod();
}
Java - Main.java
void main() {
PodeOuNao problematico = new PodeOuNao();
// para tratar exceções
// opcional tratar ou indicar que vai propagar
try {
problematico.uncheckedMethod();
} catch (Exception ex) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
}
Java - PodeOuNao.java
package marcoluglio.exceptionexample;
public final class PodeOuNao {
// checked exceptions devem ser cercadas por
// try catch ou o método deve indicar explicitamente
// que pode lançá-las com "throws"
public void checkedMethod() throws Exception {
throw new Exception("pego na compilação!");
}
// unchecked exceptions não precisam de tais
// cuidados
public void uncheckedMethod() {
throw new RuntimeException("pego na execução!");
}
}
C#
try {
throw new ArgumentException("Error"); // gera uma exceção
} catch (Exception ex) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
try {
// sem finally
} catch {
// roda se jogou uma exceção
}
try {
// sem catch
} finally {
// roda sempre
}
// não existe um tipo específico para retornar múltiplos valores
// podemos usar tipos genéricos, tuples, ou alguns métodos de
// APIs usam bool TryMetodo(out T Result), porém essa assinatura
// não retorna mais detalhes sobre o erro
Dart
// para erros que não devem ser pegos, usar a classe Error
// try on catch finally com Exception
try {
throw Exception()
} on Exception catch (ex) {
print('Exception details:\n $e');
} catch (ex, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
} finally {
//
}
// ou retorna múltiplos valores com records
// poderia definir o retorno como (int, Exception)
// e recuperar os valores pela posição apenas
({int x, Exception ex}) mayReturnError(int x) {
if (x != 0) {
return (x, null);
}
return (x, Exception());
};
var result = mayReturnError(1);
print(result.x);
print(result.ex);
print(result.$1);
print(result.$2);
try {
throw Exception("Error"); // gera uma exceção
} on (ex) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
try {
// sem on ou finally
} catch {
// roda se jogou uma exceção
}
try {
// sem on ou catch
} finally {
// roda sempre
}
TypeScript
JavaScript
try {
throw anyType; // gera uma exceção
// mas geralmente
throw new Error('Whoops!'); // gera uma exceção
} catch (e if e instanceof Error) {
// roda se jogou uma exceção
} catch (ex) {
// roda se jogou uma exceção
} finally {
// roda sempre
}
try {
// sem catch
} finally {
//
}
ActionScript
Python
try:
raise Exception("Error") # gera uma exceção
# ou simplesmente
raise # gera uma exceção
except Exception as ex:
# roda se jogou uma exceção
finally:
# roda sempre
try:
# sem finally
except:
# roda se jogou uma exceção
try:
# sem except
finally:
# roda sempre
PHP
VBA / VB6
Private Sub CapturaDeErro()
' Visual Basic não possui try catch
' Usamos labels para tratar erros
On Error GoTo Erro
' Faça alguma coisa e saia da função
' antes de chegar nas linhas de tratamento de erro
Exit Sub
' Label de erro
' Labels não podem conter espaços em branco antes dos nomes
Erro:
' Faça alguma coisa e saia da função
Exit Sub
' Ou continue a execução normalmente
Resume Next
' Ou passe para um tratamento específico
If Err.Number = 13 Then
Resume ErroEspecifico
ErroEspecifico:
Exit Sub
End Sub
Ada
-- raise begin exception when
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
-- retorna múltiplos valores com Either a b
mayReturnError :: Float -> Either String Float
mayReturnError 0 = Left "Divison by zero"
mayReturnError x = Right (x)
A página oficial do Kotlin possui alguns links e citações sobre checked exceptions. Me parece que diversos autores não recomendam seu uso.
Rust
// acompanhe essa feature
// e unstable docs
Go
-C++
#include <coroutine>
generator<int> iota(int n = 0) {
while(true) {
co_yield n++;
}
}
Objective-C
-Swift
-Kotlin
-Java
-C# - AnimadorGenerator.cs
using System.Collections.Generic;
namespace MarcoLuglio.ClosureGeneratorExample {
public class AnimadorGenerator {
// os parâmetros não podem ser ref nem out
public IEnumerable<float> Animar(float inicio, float fim, int tempo) {
var tempoAtual = 1;
var delta = (fim - inicio) / tempo;
var passo = 0f;
while (tempoAtual <= tempo) {
try {
passo = fim - (delta * (tempo - tempoAtual));
tempoAtual += 1;
yield return passo;
} finally {
// não posso usar catch com generators
}
}
// também posso usar yield break; se quiser interromper
}
}
}
C# - MainClass.cs
using System;
namespace MarcoLuglio.ClosureGeneratorExample {
public class MainClass {
public static void Main(string[] args) {
var animadorGenerator = new AnimadorGenerator();
var animadorIterator = animadorGenerator.Animar(0, 100, 9);
foreach (var resultado in animadorIterator) {
Console.WriteLine(resultado);
}
// ou
var animadorIterator = animadorGenerator.Animar(0, 100, 9).GetEnumerator();
while (animadorIterator.MoveNext()) {
var resultado = animadorIterator.Current;
Console.WriteLine(resultado);
}
}
}
}
Dart
TypeScript
JavaScript - animar.js
'use strict';
function* animar(inicio, fim, tempo) {
var tempoAtual = 1;
var delta = (fim - inicio) / tempo;
var passo = 0f;
while (tempoAtual <= tempo) {
try {
passo = fim - (delta * (tempo - tempoAtual));
tempoAtual += 1;
yield passo;
} catch (ex) {
//
}
}
}
JavaScript - main.js
'use strict';
let animadorIterador = animar(0, 100, 9);
for (let resultado of animadorIterator) {
console.log(resultado.value);
}
// ou
do {
let resultado = animadorIterador.next();
if (resultado.value || resultado.value === 0) {
console.log(resultado.value);
}
} while (!resultado.done)
ActionScript
Python
def firstn(n):
num = 0
while num < n:
yield num
num += 1
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
Go
package main
import "fmt"
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
newInts := intSeq()
fmt.Println(newInts())
}
C++
Objective-C
Swift
Kotlin
Java - AnimadorClosure.java
package marcoluglio.generatorexample;
// as assinaturas possíveis das closures estão nesse pacote
import java.util.function.*;
class ClosureState {
public int tempoAtual;
public float delta;
public Float passo;
}
public class AnimadorClosure {
public static Supplier<Float> animar(float inicio, float fim, int tempo) {
// variáveis capturadas na closure
final ClosureState closureState = new ClosureState();
closureState.tempoAtual = 1;
closureState.delta = (fim - inicio) / tempo;
closureState.passo = 0;
// closure
Supplier<Float> lambda = () -> {
if (closureState.tempoAtual <= tempo) {
closureState.passo = fim - (closureState.delta * (tempo - closureState.tempoAtual));
closureState.tempoAtual += 1;
return closureState.passo;
}
return null;
};
return lambda;
}
}
Java - Main.java
import java.util.function.*;
import marcoluglio.generatorexample.AnimadorClosure;
public class Main {
public static void main(String[] args) {
Supplier<Float> animadorClosure = AnimadorClosure.animar(0, 100, 9);
Float resultado;
do {
resultado = animadorClosure.get();
System.out.println(resultado);
} while (resultado != null);
}
}
// PS: pra evitar ter que declarar uma classe ClosureState, eu poderia ter feito
final Object closureState = new Object() {
public int tempoAtual;
public float delta;
public Float passo;
};
// mas aí para ler as propriedades eu teria que usar reflection toda a vez
Class ClosureClass = closureState.getClass();
Field TempoAtualField = ClosureClass.getDeclaredField("tempoAtual")
TempoAtualField.getInteger(closureState);
Field DeltaField = ClosureClass.getDeclaredField("delta")
DeltaField.getFloat(closureState);
Field PassoField = ClosureClass.getDeclaredField("passo")
PassoField.getFloat(closureState);
C# - AnimadorClosure.cs
namespace MarcoLuglio.GeneratorExample {
// assinatura da closure
public delegate float? Next();
public class AnimadorClosure {
public static Next Animar(float inicio, float fim, int tempo) {
// variáveis capturadas na closure
var tempoAtual = 1;
var delta = (fim - inicio) / tempo;
var passo = 0f;
// closure
Next lambda = () => {
if (tempoAtual <= tempo) {
passo = fim - (delta * (tempo - tempoAtual));
tempoAtual += 1;
return passo;
}
return null;
};
return lambda;
}
}
}
C# - MainClass.cs
using System;
namespace MarcoLuglio.GeneratorExample {
class MainClass {
public static void Main(string[] args) {
var animadorClosure = AnimadorClosure.Animar(0, 100, 9);
float? resultado;
do {
resultado = animadorClosure();
Console.WriteLine(resultado);
} while (resultado != null);
}
}
}
Dart
TypeScript
JavaScript - animarClosure.js
'use strict';
animar(inicio, fim, tempo) {
// variáveis capturadas na closure
let tempoAtual = 1;
let delta = (fim - inicio) / tempo;
let passo = 0;
// closure
let lambda = () => {
if (tempoAtual <= tempo) {
passo = fim - (delta * (tempo - tempoAtual));
tempoAtual += 1;
return passo;
}
return;
};
return lambda;
}
JavaScript - main.js
let animadorClosure = animar(0, 100, 9);
let resultado;
do {
resultado = animadorClosure();
console.log(resultado);
} while (resultado || resultado === 0);
ActionScript
Python
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
// funcionalidade experimental!
// requer versão nightly
// para habilitar implementação de FnMut
#![feature(fn_traits)]
#![feature(unboxed_closures)]
struct Animar {
fim:f32,
tempo:i32,
tempoAtual:i32,
delta:f32,
passo:f32
}
impl Animar {
fn new(inicio:f32, fim:f32, tempo:i32) -> Animar {
Animar {
fim,
tempo,
tempoAtual: 1,
delta: (fim - inicio) / (tempo as f32),
passo: 0.0
}
}
}
impl FnOnce<()> for Animar {
type Output = Option<f32>;
extern "rust-call" fn call_once(mut self, _args: ()) -> Self::Output {
self()
}
}
impl FnMut<()> for Animar {
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Option<f32> {
if self.tempoAtual <= self.tempo {
let tempoPassado = (self.tempo - self.tempoAtual) as f32;
self.passo = self.fim - (self.delta * tempoPassado);
self.tempoAtual += 1;
return Some(self.passo);
}
return None;
}
}
fn main() {
let mut animar = Animar::new(0.0, 100.0, 9);
loop {
let resultado = animar();
match resultado {
Some(some) => println!("{}", some),
None => break
}
}
}
Go
-C++ - Animar.hpp
#pragma once
class Animar final {
public:
explicit Animar(
float inicio,
float fim,
int tempo
);
~Animar();
// overload de ()
float operator()();
private:
float fim;
int tempo;
int tempoAtual;
float delta;
float passo;
};
C++ - Animar.cpp
#include "Animar.hpp";
Animar::Animar(float inicio, float fim, int tempo) {
this->fim = fim;
this->tempo = tempo;
tempoAtual = 1;
delta = (fim - inicio) / tempo;
passo = 0;
}
~Animar::Animar(float inicio, float fim, int tempo) {
//
}
// overload de ()
float Animar::operator()() {
if (tempoAtual <= tempo) {
passo = fim - (delta * (tempo - tempoAtual));
tempoAtual += 1;
return passo;
}
// TODO selecionar um valor melhor
// para indicar o fim
return 0;
}
}
C++ - Animar.hpp
#include "Animar.hpp"
int main(int argc, const char* argv[]) {
auto animar = Animar(0, 100, 9);
while (/* TODO */) {
animar();
}
return 0;
}
Objective-C
-Swift
// atual não permite overload de ()
// acompanhe essa proposta
Kotlin
class Animar constructor(inicio:Float, fim:Float, tempo:Int) {
var fim:Float
var tempo:Int
var tempoAtual:Int
var delta:Float
var passo:Float
init {
this.fim = fim
this.tempo = tempo
this.tempoAtual = 1
this.delta = (fim - inicio) / tempo
this.passo = 0f
}
// overload de ()
operator fun invoke():Float? {
if (this.tempoAtual <= this.tempo) {
this.passo = this.fim - (this.delta * (this.tempo - this.tempoAtual))
this.tempoAtual += 1
return passo
}
// TODO selecionar um valor melhor
// para indicar o fim
return null
}
}
fun main() {
var animar = Animar(0f, 100f, 9)
do {
val resultado = animar()
println(resultado)
} while (resultado != null)
}
Java
-C#
-Dart
TypeScript
JavaScript
-ActionScript
Python
class Animar(object):
def __init__(self, inicio, fim, tempo):
self.fim = fim
self.tempo = tempo
self.tempoAtual = 1
self.delta = (fim - inicio) / tempo
self.passo = 0
def __call__(self):
if (self.tempoAtual <= self.tempo):
self.passo = self.fim - (self.delta * (self.tempo - self.tempoAtual))
self.tempoAtual += 1
return self.passo
return None
animar = Animar(0, 100, 9)
while True:
result = animar()
if result is None:
break
print(result)
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
Go
C++
Objective-C
Swift
Kotlin
Java - AnimadorIterator.java
package marcoluglio.generatorexample;
import java.util.Iterator;
public class AnimadorIterator implements Iterable<Float>, Iterator<Float> {
public AnimadorIterator(float inicio, float fim, int tempo) {
this.fim = fim;
this.tempo = tempo;
this.delta = (fim - inicio) / tempo;
this.reset();
}
// region Interface Iterable<T>
@Override // "implementação explícita"
public Iterator<Float> iterator() {
return this;
}
// endregion
// region Interface Iterator<T>
@Override // "implementação explícita"
public boolean hasNext() {
if (this.tempoAtual <= this.tempo) {
return true;
}
return false;
}
@Override // "implementação explícita"
public Float next() {
this.passo = this.fim - (this.delta * (this.tempo - this.tempoAtual));
this.tempoAtual += 1;
return this.passo;
}
// endregion
private void reset() {
this.tempoAtual = 1;
this.passo = 0;
}
private final int tempo;
private int tempoAtual;
private final float fim;
private final float delta;
private float passo;
}
Java - Main.java
import marcoluglio.generatorexample.AnimadorIterator;
public class Main {
public static void main(String[] args) {
AnimadorIterator animadorIterador = new AnimadorIterator(0, 100, 9);
for (float resultado : animadorIterador) {
System.out.println(resultado);
}
}
}
C# - AnimadorIterator.cs
using System.Collections.Generic;
namespace MarcoLuglio.GeneratorExample {
public class AnimadorIterator : IEnumerable<float>, IEnumerator<float> {
public AnimadorIterator(float inicio, float fim, int tempo) {
this.fim = fim;
this.tempo = tempo;
this.delta = (fim - inicio) / tempo;
this.Reset();
}
#region interface IEnumerable
public IEnumerator<float> GetEnumerator() { // implementação implícita
return this;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return this; // implementação explícita --^
}
#endregion
#region interface IEnumerator
public bool MoveNext() { // implementação implícita
if (this.tempoAtual <= this.tempo) {
this.passo = this.fim - (this.delta * (this.tempo - this.tempoAtual));
this.tempoAtual += 1;
return true;
}
return false;
}
public float Current { // implementação implícita
get { return this.passo; }
}
object System.Collections.IEnumerator.Current { // implementação explícita
get { return this.passo; }
}
public void Reset() { // implementação implícita
this.tempoAtual = 1;
this.passo = 0;
}
public void Dispose() { /**/ } // implementação implícita
#endregion
private readonly int tempo;
private int tempoAtual;
private readonly float fim;
private readonly float delta;
private float passo;
}
}
C# - MainClass.cs
using System;
namespace MarcoLuglio.GeneratorExample {
class MainClass {
public static void Main(string[] args) {
var animadorIterator = new AnimadorIterator(0, 100, 9);
foreach (var resultado in animadorIterator) {
Console.WriteLine(resultado);
}
}
}
}
Dart
TypeScript
JavaScript - Iterator.js
class AnimadorIterator {
constructor(inicio, fim, tempo) {
Object.defineProperties(this, {
_fim: {value: fim},
_tempo: {value: tempo},
_tempoAtual: {value: tempo, writable: true},
_delta: {value: (fim - inicio / tempo)},
_passo: {value: 0, writable: true}
});
Object.seal(this);
this.reset();
}
reset() {
this._tempoAtual = 1;
this._passo = 0;
}
// iterador for of
*[Symbol.iterator]() {
if (this._tempoAtual <= this.tempo) {
this._passo = this._fim - (this._delta * (this._tempo - this._tempoAtual));
this._tempoAtual += 1;
yield this._passo;
}
}
}
JavaScript - main.js
let animadorIterator = new AnimadorIterator(0, 100, 9);
for (let resultado of animadorIterator) {
console.log(resultado);
}
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
C# - Subject.cs
// C# idiomatic (delegates)
namespace ObserverPattern {
// delegate method signature for custom events
public delegate void DelegateHandler(Object sender, CustomEventArgs e);
public sealed class Subject {
// there are many ways which we can define an event delegate function in C#
// uses default method signature
public event EventHandler StandardEventChanged = delegate {};
// uses raw method signature
public event EventHandler<CustomEventArgs> CustomEventChanged = delegate {};
// uses delegate signature alias
public event DelegateHandler DelegateChanged = delegate {};
// Action used as alias for EventHandler signature
public event Action<object?, CustomEventArgs> ActionAliasEventChanged = (sender, e) => {};
// generic Action signature
public event Action<int, bool> GenericActionEventChanged = (value1, value2) => {};
// the “event” properties will only have values assigned if
// we init them with a lambda, anonymous delegate funtion,
// reference to a function or when a delegate method is
// registered for them using +=
// which is why we need to check for null before invoking it
// if we didn’t previously initialized them
// there’s also a couple of ways to call the registered delegates
// we can mix and match how we init and call them.
private void StandardInvoke() {
// call .Invoke (does not use reflection, DynimicInvoke does, however)
this.StandardEventChanged.Invoke(this, EventArgs.Empty);
}
private void CustomInvoke(int customProperty) {
// call ?.Invoke for checking if we have delegates
// before trying to execute them
// wouldn’t be necessary since we initilized the event
// with a lambda, but I’m leaving this as an example
var customEventArgs = new CustomEventArgs();
customEventArgs.CustomProperty = customProperty;
this.CustomEventChanged?.Invoke(this, customEventArgs);
}
private void DelegateInvoke(int customProperty) {
// call it as if it was a simple function
var customEventArgs = new CustomEventArgs();
customEventArgs.CustomProperty = customProperty;
this.DelegateChanged(this, customEventArgs);
}
private void ActionAliasInvoke(int customProperty) {
// check if we have delegates before trying to
// call them as a simple function
var customEventArgs = new CustomEventArgs();
customEventArgs.CustomProperty = customProperty;
if (this.ActionAliasEventChanged != null) {
this.ActionAliasEventChanged(this, customEventArgs);
}
}
private void GenericActionInvoke(int customProperty) {
this.GenericActionEventChanged.Invoke(1, true);
}
}
}
C# - CustomEvent.cs
namespace ObserverPattern {
public sealed class CustomEventArgs : EventArgs {
public int CustomProperty { get; set; }
}
}
C# - Program.cs
using ObserverPattern;
void Subject_Changed(object? sender, EventArgs e) {
Console.WriteLine(@"Event handler");
}
void Subject_CustomEventChanged(object? sender, CustomEventArgs e) {
Console.WriteLine(e.CustomProperty);
}
void Subject_ActionAliasEventChanged(object? sender, CustomEventArgs e) {
Console.WriteLine(e.CustomProperty);
}
void Subject_GenericActionEventChanged(int arg1, bool arg2) {
Console.WriteLine(arg1.ToString(), arg2);
}
var subject = new Subject();
subject.StandardEventChanged += Subject_Changed;
subject.CustomEventChanged += Subject_CustomEventChanged;
subject.ActionAliasEventChanged += Subject_ActionAliasEventChanged;
subject.GenericActionEventChanged += Subject_GenericActionEventChanged;
// using a lambda
subject.CustomEventChanged += (object? sender, CustomEventArgs e) => {
Console.WriteLine(e.CustomProperty);
};
C# - Observer.cs
// C# observer interfaces
namespace ObserverPattern {
public sealed class Observer<T> : IObserver<T> {
#region IObserver<T> interface
public void OnCompleted() {
throw new NotImplementedException();
}
public void OnError(Exception error) {
throw new NotImplementedException();
}
public void OnNext(T value) {
Console.WriteLine(value);
}
#endregion
}
}
C# - Observable.cs
namespace ObserverPattern {
public sealed class Observable<T> : IObservable<T> {
List<IObserver<T>> observers;
public Observable() {
this.observers = new List<IObserver<T>>();
}
// this is what will broadcast the updates to observers
// it should be called whenever the value changes in the subject
// my be hard to fit this in a generic class
private void Invoke(T value) {
foreach (var observer in this.observers) {
observer.OnNext(value);
}
}
#region IObservable<T> interface
public IDisposable Subscribe(IObserver<T> observer) {
if (!this.observers.Contains(observer)) {
this.observers.Add(observer);
}
var unsubscriber = new Unsubscriber<T>(observers, observer);
return unsubscriber;
}
#endregion
}
}
C# - Unsubcriber.cs
namespace ObserverPattern {
internal sealed class Unsubscriber<T> : IDisposable {
private List<IObserver<T>> observers;
private IObserver<T> observer;
public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) {
this.observers = observers;
this.observer = observer;
}
public void Dispose() {
if (!(this.observer == null)) {
this.observers.Remove(this.observer);
}
}
}
}
C# - Program.cs
// C# observable collections
// usually used along UI
using ObserverPattern;
var observableSubject = new Observable<Subject>();
var observer = new Observer<Subject>();
observableSubject.Subscribe(observer);
// call something on observableSubject that triggers invoke
C#
// C# observable collections
using System.Collections.ObjectModel;
using System.Collections.Specialized;
void ObservableCollection_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) {
// get e.Action and collection indexes to
// find which items where added or removed
}
var observableCollection = new ObservableCollection<Subject>();
observableCollection.CollectionChanged += ObservableCollection_CollectionChanged;
observableCollection.Add(new Subject());
// C# also has an interface called INotifyPropertyChanged
// but this one is more commonly used with UI components
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
Rust
Go
package main
import (
"fmt"
"sync"
)
// exemplo go routines e channels
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x + y
case <- quit:
fmt.Println("quit")
return
}
}
}
// exemplo WaitGroup
type httpPkg struct{}
func (httpPkg) Get(url string) {}
var http httpPkg
func main() {
// go routines e channels para comunicação
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<- c)
}
quit <- 0
}()
fibonacci(c, quit)
// WaitGroup do pacote sync
var wg sync.WaitGroup
var urls = []string {
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
http.Get(url)
}(url)
}
// Espera todos os itens serem completados
wg.Wait()
}
C++ - main.cpp
#include <iostream>
#include <future>
#include <boost/algorithm/string.hpp>
#include "taskFunction.hpp"
int main(int argc, const char* argv[]) {
using std::async;
using std::string;
using std::cout;
using std::endl;
using MarcoLuglio::TaskExample::taskFunction;
// alternativa 1: método
// TODO
// alternativa 2: função
auto functionFuture = async(taskFunction, "função");
// alternativa 3: lambda
auto lambdaFuture = async([](string element) -> string {
boost::to_upper(element);
return element;
}, "lambda");
// espera os Futures calcularem um valor
// concreto antes de prosseguir
cout << functionFuture.get() << endl;
cout << lambdaFuture.get() << endl;
// c++20+ tem co_return e co_await
return 0;
}
C++ - taskFunction.hpp
#pragma once
#include <string>
namespace MarcoLuglio {
namespace TaskExample {
using std::string;
string taskFunction(string element);
}
}
C++ - taskFunction.cpp
#include <boost/algorithm/string.hpp>
#include "taskFunction.hpp"
namespace MarcoLuglio {
namespace TaskExample {
using std::string;
string taskFunction(string element) {
boost::to_upper(element);
return element;
}
}
}
Objective-C
-Swift - Console
// async await - swift 5.5+
func someFunction() async throws -> [Int] {
try await someOtherFunction()
return 1
}
// TODO use detach to call async from sync
// libdispatch ou Grande Central Dispatch
import Dispatch
// funções auxiliares para simplificar sincronização
func check(semaforo:dispatch_semaphore_t) -> Int {
let waitResult = dispatch_semaphore_wait(
semaforo,
dispatch_time(DISPATCH_TIME_NOW, 1_000_000_000)
)
return waitResult
}
func wait(semaforo:dispatch_semaphore_t) {
while check(semaforo) != 0 { /**/ }
}
// tasks
var element = "lambda"
let utilityQueue = dispatch_get_global_queue(
QOS_CLASS_UTILITY,
0
)
let semaforo = dispatch_semaphore_create(0)
dispatch_async(utilityQueue) {
element = element.uppercaseString
print(element)
dispatch_semaphore_signal(semaforo)
}
// espera os blocos terminarem antes de prosseguir
wait(semaforo)
/*
Os tipos pré-definidos de queues são:
QOS_CLASS_USER_INTERACTIVE - if it should not cause the ui to lag or hang
QOS_CLASS_USER_INITIATED - if is started by ui interaction such as a click
QOS_CLASS_UTILITY - if it is a slow operation such as io
QOS_CLASS_BACKGROUND - background tasks
*/
Swift - UI
// libdispatch ou Grande Central Dispatch
import Dispatch
// funções auxiliares para simplificar sincronização
func check(semaforo:dispatch_semaphore_t) -> Int {
let waitResult = dispatch_semaphore_wait(
semaforo,
dispatch_time(DISPATCH_TIME_NOW, 1_000_000_000)
)
return waitResult
}
func wait(semaforo:dispatch_semaphore_t) {
while check(semaforo) != 0 { /**/ }
}
// tasks
var element = "lambda"
let utilityQueue = dispatch_get_global_queue(
QOS_CLASS_UTILITY,
0
)
let semaforo = dispatch_semaphore_create(0)
dispatch_async(utilityQueue) {
element = element.uppercaseString
let mainQueue = dispatch_get_main_queue()
dispatch_async(mainQueue) {
print(element)
dispatch_semaphore_signal(semaforo)
}
}
// espera os blocos terminarem antes de prosseguir
wait(semaforo)
Kotlin
import kotlinx.coroutines.*
// runBlocking turns main into an async function
fun main() = runBlocking {
val deferred: Deferred = async {
loadData()
}
println("waiting...")
println(deferred.await())
}
suspend fun loadData(): Int {
println("loading...")
delay(1000L)
println("loaded!")
return 42
}
// channels
// https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/08_Channels
// Flow https://kotlinlang.org/docs/reference/coroutines/flow.html#flows
Java - Main.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
public class Main {
public static void main(String[] args) {
// gerencia threads
ExecutorService executor = Executors.newFixedThreadPool(2);
// alternativa 1: interface Callable
Task callableTask = new Task("async");
Future<String> taskFuture = executor.submit(callableTask);
// alternativa 2: lambda Callable
String element = "lambda";
Future<String> lambdaFuture = executor.submit(() -> {
return element.toUpperCase();
});
// alternativa 3: Threads e Futures manuais sem executor
Task manualTask = new Task("manual");
FutureTask<String> manualFuture = new FutureTask<String>(manualTask);
new Thread(manualFuture).start();
try {
// espera os Futures calcularem um valor
// concreto antes de prosseguir
System.out.println(taskFuture.get());
System.out.println(lambdaFuture.get());
System.out.println(manualFuture.get());
// encerra as threads do executor
executor.shutdown();
} catch (InterruptedException e) {
// fazer alguma coisa
} catch (ExecutionException e) {
// fazer alguma coisa
}
}
}
Java - Task.java
package marcoluglio.taskexample;
import java.util.concurrent.Callable;
public class Task implements Callable<String> {
public Task(String element) {
this.element = element;
}
@Override
public String call() throws Exception {
return this.element.toUpperCase();
}
String element;
}
Java Android - AsyncTask.java
// TODO AsyncTask
C# - MainClass.cs
using System;
namespace MarcoLuglio.TaskExample {
class MainClass {
public static void Main(string[] args) {
// async não pode ser usado no método
// main, então chamamos no objeto
// FIXME novas versões podem ter async main
var mainObject = new MainClass();
mainObject.main();
}
private async void main() {
var promise = new Promise(@"some value");
var resultado = await promise.GetResultAsync();
Console.WriteLine(@"esperou " + resultado);
}
}
}
C# - Promise.cs
using System.Threading.Tasks;
namespace MarcoLuglio.TaskExample {
public class Promise {
public Promise(string element) {
this.element = element;
}
public async Task<string> GetResultAsync() {
return this.element.ToUpper();
}
string element;
}
}
Dart
// https://pub.dev/documentation/threading/latest/
TypeScript
JavaScript
// async await
async function workAsync(element) {
return element.toUpperCase();
}
await workAsync('some value');
// ou
workAsync('some value')
.then((result) => {
console.log(result);
});
// explicit promises
function workAsync(element) {
return new Promise((resolve, reject) => {
resolve(element.toUpperCase());
});
}
workAsync('some value')
.then((result) => {
console.log(result);
});
ActionScript
Python
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
// https://stackoverflow.com/questions/3451138/simple-thread-sample-delphi
// https://edn.embarcadero.com/article/22411
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
// queue
use std::collections::vec_deque::VecDeque;
// threads
use std::thread;
// channels
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
fn uppercase(c:char) -> char {
c.to_uppercase().next().unwrap()
}
fn main() {
let mut model = VecDeque::new();
model.push_back("dislexicos");
model.push_back("devem");
model.push_back("ler");
model.push_back("frases");
model.push_back("assim");
let (senderChannel, receiverChannel)
:(Sender<&str>, Receiver<&str>)
= mpsc::channel();
// envia dados pelo canal
for element in model {
senderChannel.send(element);
}
// fecha o canal
drop(senderChannel);
// alternativa 1: thread e lambda
// move captura as variáveis no mesmo escopo
// da closure por valor ao invés de por referência
let lambda_thread = thread::spawn(move || {
let mut element:&str;
let mut elementUppercase:String;
// roda até o canal ser fechado
for element in receiverChannel {
let uppercase:String = element
.chars()
.map(uppercase)
.collect();
println!("{:?}", uppercase);
}
// poderíamos usar receiverChannel.recv().unwrap()
// e receiverChannel.try_recv().unwrap()
});
// alternativa 2: Builder e lambda
let mut builderElement = "builder";
let builder_thread = thread::Builder::new()
.name("builder thread".to_string())
.spawn(move || {
let uppercase:String = builderElement
.chars()
.map(uppercase)
.collect();
println!("{:?}", uppercase);
});
// espera as threads terminarem antes de prosseguir
lambda_thread.join();
builder_thread.unwrap().join();
}
Go
// Não possui threads
// mas veja o exemplo
// acima para sincronização
// de corrotinas
C++ - main.cpp
#include <iostream>
#include <thread>
#include <boost/algorithm/string.hpp>
#include "cout_mutex.hpp" // para simplicidade do exemplo
#include "Model.hpp"
#include "ParallelWorker.hpp"
#include "parallelWorkerFunction.hpp"
int main(int argc, const char* argv[]) {
using std::string;
using std::cout;
using std::endl;
using std::make_unique;
using std::thread;
using std::ref;
using MarcoLuglio::ThreadExample::Model;
using MarcoLuglio::ThreadExample::ParallelWorker;
using MarcoLuglio::ThreadExample::parallelWorkerFunction;
// memória compartilhada entre as threads
// como as threads não viverão mais que
// a main thread, posso usar unique_ptr
auto dataQueue = make_unique<Model>();
dataQueue.Push("dislexicos");
dataQueue.Push("devem");
dataQueue.Push("ler");
dataQueue.Push("frases");
dataQueue.Push("assim");
// alternativa 1: método
auto worker{ParallelWorker(*dataQueue)};
thread parallelThread{&ParallelWorker::Work, worker};
// alternativa 2: função
thread functionThread{parallelWorkerFunction, ref(*dataQueue)};
// alternativa 3: lambda
thread lambdaThread{[](Model& dataQueue){
string element;
auto sair = false;
while (!sair) {
element = dataQueue.Next();
// deixa a thread terminar naturalmente
if (element == "") {
sair = true;
continue;
}
boost::to_upper(element);
cout_mutex.lock();
cout << element << endl;
cout_mutex.unlock();
}
}, ref(*dataQueue)};
// espera as threads terminarem antes de prosseguir
parallelThread.join();
functionThread.join();
lambdaThread.join();
}
// TODO verificar isso tudo
// PS: unique_ptr devolve um ponteiro não copiável quando desreferenciado
auto dataQueue = make_unique<Model>();
auto copia = *dataQueue; // erro: não copiável
// por isso precisamos passar para as threads, um ponteiro do ponteiro
// ou uma referência do ponteiro
auto referenciaDoPonteiro*& = ref(dataQueue);
// ou ainda, uma referência copiável do valor apontado
auto referencia& = ref(*dataQueue);
C++ - Model.hpp
#pragma once
#include <string>
#include <queue>
#include <thread>
namespace MarcoLuglio {
namespace ThreadExample {
using std::string;
using std::queue;
using std::mutex;
// C++ possui classes nativas com acesso
// sincronizado, mas não as utilizei para
// demonstrar o uso de locks manuais
class Model final {
public:
Model();
~Model();
void Push(string);
string Next();
private:
queue<string> dataQueue;
/// Lock simples explícita para sincronização
mutex modelLock;
};
}
}
C++ - Model.cpp
#include <string>
#include <queue>
#include <thread>
#include "Model.hpp"
namespace MarcoLuglio {
namespace ThreadExample {
using std::string;
using std::queue;
using std::lock_guard;
using std::mutex;
Model::Model() {
dataQueue = queue<string>();
};
Model::~Model() {
//
};
void Model::Push(string) {
// só a main thread insere, então
// não precisa sincronizar
dataQueue.push(element);
};
string Model::Next() {
// sincroniza o acesso das threads
lock_guard<mutex> _{modelLock};
if (!dataQueue.empty()) {
string element = dataQueue.front();
dataQueue.pop();
return element;
}
// string não pode ser nullptr em c++
return "";
};
}
}
C++ - ParallelWorker.hpp
#pragma once
namespace MarcoLuglio {
namespace ThreadExample {
class Model;
class ParallelWorker final {
public:
explicit ParallelWorker(Model& model);
~ParallelWorker();
void Work();
private:
Model* dataQueue;
std::string element;
/// Flag para término da thread
bool sair;
};
}
}
C++ - ParallelWorker.cpp
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "cout_mutex.hpp" // para simplicidade do exemplo
#include "Model.hpp"
#include "ParallelWorker.hpp"
namespace MarcoLuglio {
namespace ThreadExample {
using std::cout;
using std::endl;
ParallelWorker::ParallelWorker(Model& model) {
dataQueue = &model;
sair = false;
};
ParallelWorker::~ParallelWorker() {
//
};
void ParallelWorker::Work() {
while (!sair) {
element = dataQueue->Next();
// deixa a thread terminar naturalmente
if (element == "") {
sair = true;
continue;
}
boost::to_upper(element);
cout_mutex.lock();
cout << element << endl;
cout_mutex.unlock();
}
};
}
}
C++ - parallelWorkerFunction.hpp
#pragma once
namespace MarcoLuglio {
namespace ThreadExample {
class Model;
void parallelWorkerFunction(Model& dataQueue);
}
}
C++ - parallelWorkerFunction.cpp
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "cout_mutex.hpp" // para simplicidade do exemplo
#include "Model.hpp"
#include "parallelWorkerFunction.hpp"
namespace MarcoLuglio {
namespace ThreadExample {
using std::string;
using std::cout;
using std::endl;
void parallelWorkerFunction(Model& dataQueue) {
string element;
auto sair = false;
while (!sair) {
element = dataQueue.Next();
// deixa a thread terminar naturalmente
if (element == "") {
sair = true;
continue;
}
boost::to_upper(element);
cout_mutex.lock();
cout << element << endl;
cout_mutex.unlock();
}
}
}
}
Objective-C
Swift - Cocoa threads
import Foundation
func join(thread:NSThread) {
while !thread.finished { /**/ }
}
public final class NSParallelWorker {
@objc public func work() {
// deixa a thread terminar naturalmente
while !self.sair {
print("parallel worker")
self.sair = true
}
}
private var sair:Bool = false
}
// foundation thread com métodos
let nsParallelWorker = NSParallelWorker()
let selector = #selector(NSParallelWorker.work)
let nsThread:NSThread = NSThread.init(
target: nsParallelWorker,
selector: selector,
object: nil
)
nsThread.start()
// espera as threads terminarem antes de prosseguir
join(nsThread)
Swift - POSIX threads
//int threadError = pthread_create(
// &posixThreadID,
// &attr,
// &PosixThreadMainRoutine,
// NULL
// );
let pThread:pthread_t;
let pThreadAttr:pthread_attr_t;
pthread_attr_init(UnsafeMutablePointer<pthread_attr_t>(pThreadAttr))
let threadError = pthread_create(
UnsafeMutablePointer<pthread_t>(pThread),
UnsafePointer<pthread_attr_t>(pThreadAttr),
{(UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> in
//code
}, nil)
// let modelLock:pthread_mutex_t =
// pthread_join(
// pThread,
// UnsafeMutablePointer<UnsafeMutablePointer<Void>>
// );
Kotlin - main.kt
import marcoluglio.threadexample.*
fun main() {
// memória compartilhada entre as threads
val dataQueue = Model()
dataQueue.push("dislexicos")
dataQueue.push("devem")
dataQueue.push("ler")
dataQueue.push("frases")
dataQueue.push("assim")
// alternativa 1: subclasse de Thread
val parallelThread = ParallelThread(dataQueue)
parallelThread.start()
// alternativa 2: interface Runnable
val parallelRunnable:Runnable = ParallelRunnable(dataQueue)
val parallelRunnableThread = Thread(parallelRunnable)
parallelRunnableThread.start()
// alternativa 3: lambda Runnable
// ou interface funcional Runnable
val lambda = Runnable {
var element:String?
var sair = false
while (!sair) {
// dataQueue capturado pelo lambda
element = dataQueue.next()
// deixa a thread terminar naturalmente
if (element == null) {
sair = true
continue
}
println(element.toUpperCase())
}
}
val lambdaRunnable = Thread(lambda)
lambdaRunnable.start()
// espera as threads terminarem antes de prosseguir
try {
parallelThread.join()
parallelRunnableThread.join()
lambdaRunnable.join()
} catch (e:InterruptedException) {
// fazer alguma coisa
}
}
Kotlin - Model.kt
package marcoluglio.threadexample
import kotlin.collections.ArrayList
public class Model {
private var dataQueue = ArrayList<String>()
// Lock simples explícita para sincronização
private val modelLock:Any
init {
this.modelLock = Any()
//this.dataQueue = new LinkedList<String>();
}
public fun push(element:String) {
// só a main thread insere, então
// não precisa sincronizar
this.dataQueue.add(element)
}
public fun next(): String? {
synchronized(this.modelLock) {
if (this.dataQueue.count() > 0)
return this.dataQueue.removeAt(0)
else
return null
}
}
}
Kotlin - ParallelThread.kt
package marcoluglio.threadexample
public class ParallelThread(dataQueue:Model) : Thread() {
private val dataQueue: Model
private var element: String? = null
// Flag para término da thread
private var sair = false
init {
this.dataQueue = dataQueue
}
public override fun run() {
while (!this.sair) {
this.element = this.dataQueue.next();
// deixa a thread terminar naturalmente
if (this.element == null) {
this.sair = true;
continue;
}
println(this.element?.toUpperCase());
}
}
}
Kotlin - ParallelRunnable.kt
package marcoluglio.threadexample
public class ParallelRunnable(dataQueue:Model) : Runnable {
private val dataQueue: Model
private var element: String? = null
// Flag para término da thread
private var sair = false
init {
this.dataQueue = dataQueue
}
public override fun run() {
while (!this.sair) {
this.element = this.dataQueue.next();
// deixa a thread terminar naturalmente
if (this.element == null) {
this.sair = true;
continue;
}
println(this.element?.toUpperCase());
}
}
}
Java - Main.java
public class Main {
public static void main(String[] args) {
// memória compartilhada entre as threads
Model dataQueue = new Model();
dataQueue.push("dislexicos");
dataQueue.push("devem");
dataQueue.push("ler");
dataQueue.push("frases");
dataQueue.push("assim");
// alternativa 1: subclasse de Thread
ParallelThread parallelThread = new ParallelThread(dataQueue);
parallelThread.start();
// alternativa 2: interface Runnable
Runnable parallelRunnable = new ParallelRunnable(dataQueue);
Thread parallelRunnableThread = new Thread(parallelRunnable);
parallelRunnableThread.start();
// alternativa 3: lambda Runnable
// ou interface funcional Runnable
Runnable lambda = () -> {
String element;
boolean sair = false;
while (!sair) {
// dataQueue capturado pelo lambda
element = dataQueue.next();
// deixa a thread terminar naturalmente
if (element == null) {
sair = true;
continue;
}
System.out.println(element.toUpperCase());
}
};
Thread lambdaRunnable = new Thread(lambda);
lambdaRunnable.start();
// espera as threads terminarem antes de prosseguir
try {
parallelThread.join();
parallelRunnableThread.join();
lambdaRunnable.join();
} catch (InterruptedException e) {
// fazer alguma coisa
}
}
}
Java - Model.java
package marcoluglio.threadexample;
import java.util.LinkedList;
// Java possui classes nativas com acesso
// sincronizado, mas não as utilizei para
// demonstrar o uso de locks manuais
public final class Model {
public Model() {
this.modelLock = new Object();
this.dataQueue = new LinkedList<String>();
}
public void push(String element) {
// só a main thread insere, então
// não precisa sincronizar
this.dataQueue.add(element);
}
public String next() {
// sincroniza o acesso das threads
synchronized(this.modelLock) {
return this.dataQueue.poll();
}
}
private LinkedList<String> dataQueue;
// Lock simples explícita para sincronização
private final Object modelLock;
}
Java - ParallelThread.java
package marcoluglio.threadexample;
public final class ParallelThread extends Thread {
public ParallelThread(Model dataQueue) {
this.dataQueue = dataQueue;
}
// método "main" da thread
@Override
public void run() {
while (!this.sair) {
this.element = this.dataQueue.next();
// deixa a thread terminar naturalmente
if (this.element == null) {
this.sair = true;
continue;
}
System.out.println(this.element.toUpperCase());
}
}
private Model dataQueue;
private String element;
// Flag para término da thread
private boolean sair = false;
}
Java - ParallelRunnable.java
package marcoluglio.threadexample;
public final class ParallelRunnable implements Runnable {
public ParallelRunnable(Model dataQueue) {
this.dataQueue = dataQueue;
}
// método "main" da thread
@Override
public void run() {
while (!this.sair) {
this.element = this.dataQueue.next();
// deixa a thread terminar naturalmente
if (this.element == null) {
this.sair = true;
continue;
}
System.out.println(this.element.toUpperCase());
}
}
private Model dataQueue;
private String element;
// Flag para término da thread
private boolean sair = false;
}
C# - MainClass.cs
using System;
using System.Threading;
namespace MarcoLuglio.ThreadExample {
public class MainClass {
public static void Main(string[] args) {
// memória compartilhada entre as threads
var dataQueue = new Model();
dataQueue.Push("dislexicos");
dataQueue.Push("devem");
dataQueue.Push("ler");
dataQueue.Push("frases");
dataQueue.Push("assim");
// alternativa 1: método
var worker = new ParallelWorker(dataQueue);
var parallelThread = new Thread(worker.Work);
parallelThread.Start();
// alternativa 2: lambda
var lambdaThread = new Thread(() => {
string element;
var sair = false;
while (!sair) {
// dataQueue capturado pelo lambda
element = dataQueue.Next();
// deixa a thread terminar naturalmente
if (element == null) {
sair = true;
continue;
}
Console.WriteLine(element.ToUpper());
}
});
lambdaThread.Start();
// espera as threads terminarem antes de prosseguir
parallelThread.Join();
lambdaThread.Join();
}
}
}
C# - Model.cs
using System.Collections.Generic;
namespace MarcoLuglio.ThreadExample {
// C# possui classes nativas com acesso
// sincronizado, mas não as utilizei para
// demonstrar o uso de locks manuais
public sealed class Model {
public Model() {
this.modelLock = new object();
this.dataQueue = new Queue<string>();
}
public void Push(string element) {
// só a main thread insere, então
// não precisa sincronizar
this.dataQueue.Enqueue(element);
}
public string Next() {
// sincroniza o acesso das threads
lock (this.modelLock) {
if (this.dataQueue.Count == 0) {
return null;
}
return this.dataQueue.Dequeue();
}
}
private readonly Queue<string> dataQueue;
/// <summary>
/// Lock simples explícita para sincronização
/// </summary>
private readonly object modelLock;
}
}
C# - ParallelWorker.cs
using System;
namespace MarcoLuglio.ThreadExample {
public sealed class ParallelWorker {
public ParallelWorker(Model dataQueue) {
this.dataQueue = dataQueue;
}
// método "Main" da thread
public void Work() {
while (!this.sair) {
this.element = this.dataQueue.Next();
// deixa a thread terminar naturalmente
if (this.element == null) {
this.sair = true;
continue;
}
Console.WriteLine(this.element.ToUpper());
}
}
private Model dataQueue;
private string element;
/// <summary>
/// Flag para término da thread
/// </summary>
private bool sair = false;
}
}
JavaScript - main.js
'use strict';
// cria a worker thread de uso exclusivo
// da main thread
let webWorker = new Worker('worker.js');
// web workers não compartilham memória
// apenas trocam mensagens entre si
// e não podem acessar o DOM
// envia mensagens para a worker thread
webWorker.postMessage(['algum', 'valor']);
webWorker.postMessage([10, 20]);
// callback para recepção de mensagens
// da worker thread
webWorker.onmessage = (event) => {
console.log(event.data);
};
// mata a thread imediatamente se quiser
// webWorker.terminate();
JavaScript - worker.js
'use strict';
// callback para recepção de mensagens
// da main thread (ui thread)
onmessage = (event) => {
console.log(event.data[0]);
console.log(event.data[1]);
let result = event.data.join(' ');
// envia mensagens para a main thread
postMessage(result);
// termina a thread se quiser
// close();
};
Dart
TypeScript
JavaScript - sharedThread1.js
'use strict';
// cria uma worker thread compartilhada
let webWorkerOp1 = new SharedWorker('worker.js');
// envia mensagens para a worker thread compartilhada
webWorkerOp1.port.postMessage(['algum', 'valor']);
webWorkerOp1.port.postMessage([10, 20]);
// callback para recepção de mensagens
// da worker thread
webWorkerOp1.port.onmessage = (event) => {
console.log(event.data);
};
JavaScript - sharedThread2.js
'use strict';
// cria uma worker thread compartilhada
let webWorkerOp2 = new SharedWorker('worker.js');
// envia mensagens para a worker thread compartilhada
webWorkerOp2.port.postMessage(['misturar', 2]);
webWorkerOp2.port.postMessage([10, 20]);
// callback para recepção de mensagens
// da worker thread
webWorkerOp2.port.onmessage = (event) => {
console.log(event.data);
};
JavaScript - worker.js
'use strict';
onconnect = (event) => {
let port = event.ports[0];
// callback para recepção de mensagens
// da main thread (ui thread)
port.onmessage = (event) => {
console.log(event.data[0]);
console.log(event.data[1]);
let result = event.data.join(' ');
// envia mensagens para a main thread
port.postMessage(result);
// termina a thread se quiser
// close();
};
};
ActionScript
Python
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
threadLock.acquire()
# TODO
threadLock.release()
threadLock = threading.Lock()
threads = []
thread1 = myThread(1, 'Thread-1')
thread2 = myThread(2, 'Thread-2')
threads.append(thread1)
threads.append(thread2)
for t in threads:
t.start()
for t in threads:
t.join()
#def main():
# x = threading.Thread(target=thread_function, args=(1,))
# x.start()
# x.join()
PHP
VBA / VB6
-Ada
// https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/chapters/11_Concurrency.html
Object Pascal (Delphi)
Ruby
# https://ruby-doc.org/core-2.5.0/Thread.html
Smalltalk
Common Lisp
Haskell
A
Rust
// TODO rust tem vários atributos
// TODO macros também são pré-processados
// compilação condicional com #cfg é um deles
// copiado de rust by example e docs oficiais
#[cfg(...)]
#[cfg(target_os = "macos")]
#[cfg(any(foo, bar))]
#[cfg(all(unix, target_pointer_width = "32"))]
#[cfg(not(foo))]
#[cfg(target_os = "linux")]
fn are_you_on_linux() {
println!("You are running linux!")
}
// function only gets compiled if target OS is *not* linux
#[cfg(not(target_os = "linux"))]
fn are_you_on_linux() {
println!("You are *not* running linux!")
}
fn main() {
are_you_on_linux();
println!("Are you sure?");
if cfg!(target_os = "linux") {
println!("Yes. It's definitely linux!");
} else {
println!("Yes. It's definitely *not* linux!");
}
}
/*
debug_assertions - Enabled by default when compiling
without optimizations. This can be used to enable extra
debugging code in development but not in production.
For example, it controls the behavior of the
standard library's debug_assert! macro.
target_arch = "..." - "x86", "x86_64", "mips",
"powerpc", "powerpc64", "arm", or "aarch64".
target_endian = "..." - "little", "big".
target_env = ".." - musl, msvc, gnu or blank
target_family = "..." - "unix" or "windows".
target_os = "..." - "windows", "macos", "ios", "linux",
"android", "freebsd", "dragonfly", "bitrig" , "openbsd"
or "netbsd".
target_pointer_width = "..." - "32" or "64"
target_vendor = "..." - apple, pc, "unknown".
test - Enabled when compiling the test harness
(using the --test flag).
unix - See target_family.
windows - See target_family.
*/
Go
//go:noescape
//go:uintptrescapes
//go:noinline
//go:norace
//go:nosplit
//go:linkname localname [importpath.name]
//line :line
//line :line:col
//line filename:line
//line filename:line:col
/*line :line*/
/*line :line:col*/
/*line filename:line*/
/*line filename:line:col*/
C++
#include <iostream>
#include "somelib.h"
#pragma once
#ifndef __some_identifier__
#define __some_identifier__
// rest of code
#endif
Objective-C
#include <iostream>
#include "somelib.h"
#ifndef __some_identifier__
#define __some_identifier__
// rest of code
#endif
Swift
/*
os() OSX, iOS, watchOS, tvOS, Linux
arch() x86_64, arm, arm64, i386
swift() >= followed by a version number
*/
#if os(iOS) && !swift(>= 2)
// statements
#elseif os(OSX)
// statements
#else
// statements
#endif
Kotlin
-Java
-C#
// não podem ter whitespace antes!
#if DEBUG
//
#elif TRACE
//
#else
//
#endif
// TODO ver oq o visual studio fornece
#define TESTE
#if TESTE
#warning TESTE is defined
// ou
#error TESTE is defined
#endif
#undef TESTE
// desabilitar avisos do compilador
#pragma warning disable 414, 3021
[CLSCompliant(false)]
public class C {
static void Main() {}
}
#pragma warning restore 414, 3021
// garantir checksums de arquivos
#pragma checksum "filename.cs" "{3673e4ca-6098-4ec1-890f-8fceb2a794a2}" "{012345678AB}"
// guid --^ checksum bytes --^
// #line é mais usado por source generators
// força step over pelo debugger
#line hidden
#line 837 "Meio inútil"
#line default
Dart
TypeScript
/// <reference path="…" />
/// <reference types="…" />
/// <reference lib="…" />
/// <reference no-default-lib="true" />
/// <amd-module />
/// <amd-dependency />
JavaScript
'use strict'; // modo estrito
ActionScript
Python
PHP
VBA / VB6
Option Compare
Option Explicit
#Const DEBUG = 1
#If DEBUG = 1 Then
'Código de debug
#Else
'Código normal
#End If
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
let some_tuple = (1u8, 2u16, 2f32);
some_tuple.0;
Go
-C++
#include <tuple>
auto valores{std::make_tuple(3.8, 'A', "Lisa Simpson")};
auto valoresCpp17{1, -1};
std::get<0>(valores);
Objective-C
-Swift
let someTuple: (Double, Double, Double) = (3.14159, 2.71828, 1.1)
someTuple.0
// lembrando que uma tuple vazia em swift significa Void
// () > ()
// () > Void
Kotlin
Java
-C#
// tuple literals - C# 7+
var population = ("New York", 7891957, 7781984); // com índices // TODO verificar isso
var population = (a:"New York", b:7891957, c:7781984); // com nomes // TODO verificar isso
// tuple classes
var population = new Tuple<string, int, int>("New York", 7891957, 7781984);
population.Item1;
Dart
TypeScript
JavaScript
-ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust e Swift lidam com tuples de modo bastante integrado à linguagem.
C++ e C# tratam tuples como se fossem uma funcionalidade construída sobre o paradigma de orientaçµão à objetos.
Rust
enum WithoutValues {
A,
B,
C
}
// podemos misturar os tipos
enum WithValues {
A(i32),
B(i32, i32),
C(String)
}
let someEnum = WithValues::B(1, 2);
Go
// use constantes + iota
const (
a = 1 << iota // a == 1 (iota has been reset)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
C++
Objective-C
Swift
enum GamePad {
case XboxOne
case XboxEliteSeries2
case Dualshock4
case DualSense
case JoyCon
}
// implicit raw values
enum PreviousGameConsole:UInt8 {
case Xbox360 = 0x00
case PlayStation4 // 0x01
case WiiU // 0x02
}
// explicit values
enum GameConsole:UInt8 {
case XboxSeriesX = 0x00
case PlayStation5 = 0x01
case NintendoSwitch = 0x02
}
// to raw value
let gameConsole = GameConsoles.NintendoSwitch.rawValue // 0x02
// from raw value
let playstation5 = GameConsole(rawValue: 0x01)
// associated values of different types
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
// iterable
enum Beverage:CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
for beverage in Beverage.allCases {
print(beverage)
}
// recursivamente
// TODO
Kotlin
Java
C#
Dart
TypeScript
JavaScript
// ver Symbol
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
// Devemos inicializar todos os campos
// da struct com a sintaxe de chaves
// antes de poder usá-la
pub struct ResultadoCaixa {
pub total:i32,
pub valorPago:i32,
pub troco:i32,
}
let mut compra1 = ResultadoCaixa{
total: 967,
valorPago: 1000,
troco: 33
};
// structs podem ter métodos
// métodos podem ou não modificar a struct
// dependendo de como recebem o argumento
// self. Se &self ou &mut self
impl ResultadoCaixa {
pub fn descontarFidelidade(&mut self) {
self.total = self.calcularFidelidade();
self.troco = self.valorPago - self.total;
}
fn calcularFidelidade(&self) -> i32 {
self.total - 1
}
}
// structs não herdam de um objeto comum
// Nem suportam herança
// No entanto, podem implementar traits
trait Parcelavel {
fn parcelar(&self) -> [i32; 3];
}
impl Parcelavel for ResultadoCaixa {
fn parcelar(&self) -> [i32; 3] {
//
}
}
Go
package main
import "fmt"
type SomeBaseStruct struct {
a int32
}
// structs não suportam herança
// mas tem um atalho para fazer composição
type SomeStruct struct {
SomeBaseStruct // composição
x int32
}
// structs podem ter métodos
func (s *SomeStruct) getX() int32 {
return s.x
}
func (s *SomeStruct) setX(newValue int32) {
s.x = newValue
}
func setToTen(s *SomeStruct) {
s.setX(10)
}
func main() {
s1 := SomeStruct {
x: 2, // vírgula dangling não é um erro, é obrigatório
}
s2 := SomeStruct {
x: 2} // ou então } tem que vir na mesma linha
// mesmo que c++, se passar por valor faz uma cópia sem avisar
setToTen(&s2)
fmt.Println(s1.x)
fmt.Println(s2.x)
}
C++
// structs e classes são idênticas
// em C++ exceto por uma única diferença
// por padrão os campos das structs são
// publicos, e os das classes são privados
Objective-C
// Objective-C usa structs do C
// que são um simples agrupamento
// de variáveis sem nenhuma outra
// funcionalidade extra
struct ResultadoCaixa {
int total;
int valorPago;
int troco;
};
// sempre que utilizarmos o nome
// do tipo definido com uma struct
// precisamos incluir a palavra struct
// antes do nome do tipo
struct ResultadoCaixa compra1 = {
.total = 967,
.valorPago = 1000,
.troco = 33
};
// ou
struct ResultadoCaixa compra1;
compra1.total = 967;
compra1.valorPago = 1000;
compra1.troco = 33;
// ou ainda
struct ResultadoCaixa compra1 = {
967,
1000,
33
};
Swift
// Devemos inicializar todos os campos
// da struct com o inicializador gerado
// automaticamente antes de poder usá-la
public struct ResultadoCaixa {
public var total:Int
public var valorPago:Int
public var troco:Int
}
let compra1 = ResultadoCaixa(
total: 967,
valorPago: 1000,
troco: 33
)
// structs podem ter métodos
// por padrão, métodos não podem modificar a struct
// mas podem ser marcados com a palavra mutating
// para indicar este intuito
public struct ResultadoCaixaFidelidade {
public mutating func descontarFidelidade() {
self.total = self.calcularFidelidade()
self.troco = self.valorPago - self.total
}
private func calcularFidelidade() -> Int {
return total - 1
}
public var total:Int
public var valorPago:Int
public var troco:Int
}
// structs não herdam de um objeto comum
// Nem suportam herança
// No entanto, podem implementar protocolos
// Embora o resultado seja bastante confuso
// em termos de alocação de memória
public protocol Parcelavel {
func parcelar():[Int]
}
public struct ResultadoCaixaCartao : Parcelavel {
public func parcelar():[Int] {
//
}
}
Kotlin
// data classes NÃO SÃO structs
// mas tem um propósito similar
public data class ResultadoCaixa(
val total:Int,
val valorPago:Int,
var troco:Int
)
val compra1 = ResultadoCaixa(
total = 967,
valorPago = 1000,
troco = 33
)
Java
// java 15+
// records NÃO SÃO structs
// mas tem um propósito similar
public record ResultadoCaixa(
int total,
int valorPago,
int troco
){}
var compra1 = ResultadoCaixa(
967,
1000,
33
);
C#
// Se criada sem new os campos
// são iniciados manualmente
public struct ResultadoCaixa {
public int total;
public int valorPago;
public int troco;
}
ResultadoCaixa compra1;
compra1.total = 967; // 9,67
compra1.valorPago = 1000; // 10,00
compra1.troco = 33; // 00,33
// Se criada com new os campos
// são iniciados no construtor
public struct ResultadoCaixaC {
ResultadoCaixaC(int total, int valorPago) {
this.total = total;
this.valorPago = valorPago;
this.troco = valorPago - total;
}
public int total;
public int valorPago;
public int troco;
}
var compra2 = new ResultadoCaixaC(967, 1000);
// structs podem ter métodos
public struct ResultadoCaixaFidelidade {
public void descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
private int calcularFidelidade() {
return this.total - 1;
}
public int total;
public int valorPago;
public int troco;
}
// structs herdam de Object
Console.WriteLine(resultado is Object); // true
// Mas NÃO suportam heranças subsequentes
public struct ResultadoCaixaFidelidade2 : ResultadoCaixa {} // erro
// No entanto, podem implementar interfaces
// Embora o resultado seja bastante confuso
// em termos de alocação de memória
public interface Parcelavel {
int[] Parcelar();
}
public struct ResultadoCaixaCartao : Parcelavel { // ok
public int[] Parcelar() {
//
}
}
// c# 9+
// records NÃO SÃO structs
// mas tem um propósito similar
// record chegou a ser anunciado como data class antes da versão final
public record Person {
public string FirstName { get; init; }
public string LastName { get; init; }
}
var person = new Person("Scott", "Hunter"); // positional construction
var otherPerson = person with { LastName = "Hanselman" }; // with
Dart
TypeScript
JavaScript
-ActionScript
Python
# python 3.7+
# data classes NÃO SÃO structs
# mas tem um propósito similar
@dataclass(eq = True, unsafe_hash = False, frozen = False)
class ResultadoCaixa:
total:int
valorPago:int
troco:int
compra1 = ResultadoCaixa(967, 1000, 33)
PHP
// acompanhe essa feature
// meanwhile use associative arrays
// TODO
VBA / VB6
' User Defined Types (UDTs) se parecem com structs
'Definimos o tipo num arquivo .bas separado
Public Type ResultadoCaixa
Total As Integer
ValorPago As Integer
Troco As Integer
End Type
Dim compra1 As ResultadoCaixa
compra1.total = 967; ' 9,67
compra1.valorPago = 1000; ' 10,00
compra1.troco = 33; ' 00,33
' ou com With
With compra1
.total = 967; ' 9,67
.valorPago = 1000; ' 10,00
.troco = 33; ' 00,33
End With
Ada
Object Pascal (Delphi)
type TResultadoCaixa = record
Total:Integer;
ValorPago:Integer;
Troco:Integer;
end;
program Main;
var compra1:TResultadoCaixa;
begin
compra1.Total := 967;
compra1.ValorPago := 1000;
compra1.Troco := 33;
// ou com with
with compra1 do
begin
Total := 967;
ValorPago := 1000;
Troco := 33;
end;
end.
// structs podem ter a parte final
// variável
type TResultadoCaixa2 = record
fieldList1:type1;
...
fieldListn:typen;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;
// structs podem ter construtores, métodos, getters e setters
type TResultadoCaixa3 = record
constructor Create(total:Integer, valorPago:Integer);
// property RedProperty: TInnerColorType read Red write Red;
procedure DescontarFidelidade();
function CalcularFidelidade():Integer;
Total:Integer;
ValorPago:Integer;
Troco:Integer;
end;
constructor TResultadoCaixa3.Create(Total:Integer, ValorPago:Integer);
begin
Self.Total := Total;
Self.ValorPago := ValorPago;
Self.Troco := ValorPago - Total;
end;
procedure TResultadoCaixa3.DescontarFidelidade;
begin
Self.Total := Self.CalcularFidelidade();
Self.Troco := Self.ValorPago - Self.Total;
end;
function TResultadoCaixa3.CalcularFidelidade:Integer;
begin
Result := Self.Total - 1;
end;
Ruby
ResultadoCaixa = Struct.new(
:total,
:valorPago,
:troco
)
compra1 = ResultadoCaixa.new(
967,
1000,
33
)
# structs podem ter métodos, getters e setters
ResultadoCaixa = Struct.new(
:total,
:valorPago,
:troco
) do
def descontarFidelidade
self.total = self.calcularFidelidade() # TODO
self.troco = self.valorPago - self.total
end
def calcularFidelidade
return self.total - 1
end
end
Smalltalk
Common Lisp
Haskell
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
Rust
-Go
-C++
Objective-C
-Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
-ActionScript
-Python
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
F#
Web Assembly text format
-LLVM IR
Assembly
-A
Rust
-Go
-C++ - ResultadoCaixa.hpp
#pragma once
class ResultadoCaixa final {
public:
explicit ResultadoCaixa(const int total, const int valorPago);
~ResultadoCaixa();
void descontarFidelidade();
private:
// por padrão, métodos podem modificar a classe
// mas podem ser marcados com a palavra const
// para proibir este intuito
int calcularFidelidade() const;
int total;
int valorPago;
int troco;
};
C++ - ResultadoCaixa.cpp
#include "ResultadoCaixa.hpp"
ResultadoCaixa::ResultadoCaixa(const int total, const int valorPago)
: total{total}, valorPago{valorPago} {
this->troco = valorPago - total;
}
ResultadoCaixa::~ResultadoCaixa() {
//
}
ResultadoCaixa::descontarFidelidade() {
this->total = calcularFidelidade();
this->troco = valorPago - total;
}
int ResultadoCaixa::calcularFidelidade() const {
return total - 1;
}
C++ - main.cpp
#include "ResultadoCaixa.hpp"
int main(int argc, const char* argv[]) {
// aloca na stack
auto compra1 = ResultadoCaixa(997, 1000);
compra1.descontarFidelidade();
// aloca na heap
auto compra2 = new ResultadoCaixa(997, 1000);
compra2.descontarFidelidade();
return 0;
}
Objective-C - ResultadoCaixa.h
#import <Foundation/Foundation.h>
@interface ResultadoCaixa : NSObject {
// instance variables ou ivars
@private
int _troco;
}
- (void) descontarFidelidade;
- (int) calcularFidelidade;
// propriedades
@property (assign, nonatomic) int total;
@property (assign, nonatomic) int valorPago;
@end
Objective-C - ResultadoCaixa.m
#import "ResultadoCaixa.h"
@implementation ResultadoCaixa
- (id) initWithTotal:(int)novoTotal eValorPago:(int)novoValorPago {
[self init];
// propriedades são acessadas com .
self.total = novoTotal;
self.valorPago = novoValorPago;
// ivars são acessadas com ->
self->_troco = self.valorPago - self.total;
return self;
}
- (void) descontarFidelidade {
self.total = [self calcularFidelidade];
self->_troco = self.valorPago - self.total;
}
- (int) calcularFidelidade {
return self.total - 1;
}
@end
Objective-C - main.m
#import "ResultadoCaixa.h"
int main(int argc, const char* argv[]) {
ResultadoCaixa* compra1 = [[ResultadoCaixa alloc] initWithTotal:997 eValorPago:1000];
[compra1 descontarFidelidade];
return 0;
}
Swift
public final class ResultadoCaixa {
init(total:Int, valorPago:Int) {
self.total = total
self.valorPago = valorPago
self.troco = valorPago - total
}
public func descontarFidelidade() {
self.total = self.calcularFidelidade()
self.troco = self.valorPago - self.total
}
private func calcularFidelidade() -> Int {
return self.total - 1
}
private var total = 0
private var valorPago = 0
private var troco = 0
}
let compra1 = ResultadoCaixa()
compra1.descontarFidelidade()
class C {
static func myStaticMethod() {
//
}
static var myStaticProp:String
deinit {
//
}
lazy var prop:String
}
final class D : C, P, Q {
override init() {
super.init()
}
init?() {
return nil
}
convenience init() {
//
}
// o override pode ser mais visível!
override internal func myMethod() {
super.myMethod()
}
}
final class R {
required init() {
//
}
}
Kotlin - ResultadoCaixa.kt
public class ResultadoCaixa(total:Int, valorPago:Int) {
public fun descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
private fun calcularFidelidade():Int {
return this.total - 1;
}
var total = total
val valorPago = valorPago
var troco = valorPago - total
lateinit var prop:String
}
// OU
public class ResultadoCaixa constructor(val total:Int, val valorPago:Int) {
init {
this.total = total
this.valorPago = valorPago
this.troco = valorPago - total
}
public fun descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
private fun calcularFidelidade():Int {
return this.total - 1;
}
var total:Int
val valorPago:Int
var troco:Int
}
val compra1 = ResultadoCaixa(997, 1000)
compra1.descontarFidelidade()
open class C {
}
class D : C, P, Q {
//
}
Kotlin - Main.kt
Java - ResultadoCaixa.java
public final class ResultadoCaixa {
public ResultadoCaixa(int total, int valorPago) {
this.total = total;
this.valorPago = valorPago;
this.troco = this.valorPago - this.total;
}
public void descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
private int calcularFidelidade() {
return this.total - 1;
}
private int total = 0;
// variáveis final não podem ser alteradas
// após seu valor ter sido especificado
private final int valorPago;
private int troco = 0;
}
Java - Main.java
public class Main {
public static void main(string[] args) {
ResultadoCaixa compra1 = new ResultadoCaixa(997, 1000);
compra1.descontarFidelidade();
}
}
C# - ResultadoCaixa.cs
public sealed class ResultadoCaixa {
public ResultadoCaixa(int total, int valorPago) {
this.total = total;
this.valorPago = valorPago;
this.troco = this.valorPago - this.total;
}
public void descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
// c# 7
private int calcularFidelidade => this.total - 1;
private int total = 0;
// propriedades readonly só podem ser modificadas
// dentro do construtor
private readonly int valorPago;
private int troco = 0;
}
C# - MainClass.cs
public class MainClass {
public static void Main(string[] args) {
// argumentos por posição
var compra1 = new ResultadoCaixa(997, 1000);
compra1.descontarFidelidade();
// argumentos nomeados
var compra2 = new ResultadoCaixa(total:997, valorPago:1000);
compra2.descontarFidelidade();
}
}
Dart
TypeScript
JavaScript
// note que JavaScript não possui classes de verdade
// apenas objetos que herdam de outros objetos diretamente
// prototype based inheritance
const ResultadoCaixa = class ResultadoCaixa {
constructor(total, valorPago) {
Object.defineProperties(this, {
total: {value: total, writable: true},
valorPago: {value: valorPago}, // não writable por padrão
troco: {value: valorPago - total, writable: true}
});
Object.seal(this);
}
descontarFidelidade() {
this.total = this.calcularFidelidade();
this.troco = this.valorPago - this.total;
}
calcularFidelidade() {
return this.total - 1;
}
};
const compra1 = new ResultadoCaixa(997, 1000);
compra1.descontarFidelidade();
ActionScript
Python
class ResultadoCaixa:
def __init__(self, total, valorPago):
self.total = total
self.valorPago = valorPago
self.troco = self.valorPago - self.total
def descontarFidelidade(self):
self.total = self.calcularFidelidade()
self.troco = self.valorPago - self.total
def calcularFidelidade(self):
return self.total - 1
compra1 = ResultadoCaixa(997, 1000)
compra1.descontarFidelidade()
PHP
VBA / VB6 - ResultadoCaixa.cls
'Evento
Public Event OnChange(ByVal valorNovo As Byte, ByVal valorAntigo As Byte)
'Variável pública, pode ser acessada diretamente
Public publicVar As Boolean
'Variáveis privadas acessadas pelas propriedades
Private prop1 As Boolean
Private friendProp1 As Boolean
'Getter
Public Property Get Prop1() As Boolean
Prop1 = prop1
End Property
'Setter de tipos primitivos usa Let
Public Property Let Prop1(ByVal value As Boolean)
prop1 = value
End Property
'Setter de objetos usa Set
'Friend permite acesso por outros objetos do mesmo projeto / dll
'Não tem relação nenhuma com a funcionalidade em c++
Friend Property Get FriendProp1() As Boolean
FriendProp1 = friendProp1
End Property
Public Sub Metodo1()
RaiseEvent OnChange(1, 2)
'Podemos nos registrar para responder à esse evento usando no nosso form
'Private Sub Instance_OnChange(ByVal valorNovo As Byte, ByVal valorAntigo As Byte)
'...
'End Sub
End Sub
Public Function Metodo2() As Boolean
'...
End Function
Friend Function MetodoFriend(Optional ByVal argOpcional1 As Boolean = True) As Boolean
'...
End Function
VBA / VB6 - Main.bas
Dim compra1 As ResultadoCaixa
Set compra1 = new ResutadoCaixa
' TODO
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
(defclass resultadoCaixa() (
(name
:initarg :name
:accessor name
)
(lisper
:initform nil
:accessor lisper
)
))
Haskell
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
Rust
-Go
-C++
-Objective-C - A.h
#import <Foundation/Foundation.h>
@interface A : NSObject
@property (assign, nonatomic) NSString* prop;
@property (assign, nonatomic) NSString* prop2;
@end
Objective-C - A.m
#import "A.h"
@implementation A
@end
Objective-C - main.m
#import "A.h"
int main(int argc, const char* argv[]) {
A* a = [[A alloc] init];
a.prop = @"";
return 0;
}
Swift
public final class A {
init() {
//
}
var getter:String {
return ...
}
var getterSetter:String {
get {
return self._getterSetter
}
set(newValue) { // ou newValue implícito set {
self._getterSetter = newValue
}
}
private _getterSetter:String
// setter pode ser menos visível que o getter
public private(set) var numberOfEdits = 0
// internal
private(set) var numberOfEdits = 0
}
var a = A()
a.prop = ""
Kotlin
// as classes são final por padrão
// não confundir com sealed class
// que quer dizer outra coisa
class A {
init {
//
}
// getter
var stringRepresentation:String
get() = this.toString()
// getter e setter
var stringRepresentation2:String
get() = this.toString()
set(value) {
setDataFromString(value)
}
// com visibilidades diferentes
var stringRepresentation3:String
get() = this.toString()
private set(value) {
setDataFromString(value)
}
}
Java
// não tem getters e setters implícitos
// tem que usar métodos com convenção de nome
// começando com Get ou Set
C# - ResultadoCaixa.cs
public sealed class A {
public A() {
//
}
public string Prop {
get;
set;
}
// c# 7
public string Prop2 {
get => "";
set => this.prop2 = value;
}
public string Prop3 {
get {
return "";
}
set {
this.prop3 = value;
}
}
private string prop2;
private string prop3;
}
C# - MainClass.cs
public class MainClass {
public static void Main(string[] args) {
// argumentos por posição
var a = new A();
a.prop = @"";
a.prop2 = @"";
}
}
Dart
TypeScript
JavaScript
const A = class A {
constructor() {
Object.defineProperty(
this,
'_prop',
{value: null, writable: true}
);
Object.seal(this);
}
get prop() {
return this._prop;
}
set prop(newValue) {
this._prop = newValue;
}
};
const a = new A();
a.prop = '';
ActionScript
Python
class A:
def __init__(self, prop = 0):
self.prop = prop
@property
def prop(self):
return self._prop
@prop.setter
def prop(self, value):
self._prop = value
PHP
VBA / VB6
Option Explicit
Private m_prop As String
Private Sub Class_Initialize()
m_name = ""
End Sub
Public Property Get Prop() as String
Prop = m_name
End Property
Public Property Let Prop(ByVal Value As String)
m_prop = Value
End Property
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
trait HasArea {
fn is_invalid(&self) -> bool { !self.is_valid() }
}
impl HasArea for Circle {
// is_invalid "herdado"
}
Go
// Possui atalhos para composição de objetos
C++
// Herança múltipla tem
// funcionalidade similar
// às traits
Objective-C - Traits.h
@interface Person (Traits)
- (void) addFriend:(Person *)aFriend;
- (void) removeFriend:(Person *)aFriend;
- (void) sayHelloToFriends;
@end
Objective-C - Traits.m
#import "Person+Relations.h"
@implementation Person (Traits)
- (void) addFriend:(Person*)aFriend {
[[self friends] addObject:aFriend];
}
- (void) removeFriend:(Person*)aFriend {
[[self friends] removeObject:aFriend];
}
- (void) sayHelloToFriends {
for (Person* friend in [self friends]) {
NSLog(@"Hello there, %@!", [friend name]);
}
}
@end
Swift
extension ClassToBeExtended {
// posso adicionar initializers
// métodos
// e propriedades
}
Kotlin
fun ClassToBeExtended.extensionMethod() {
//
}
// ou como Java 8
public interface Desenhavel {
desenhar() {
//
}
}
Java
public interface Desenhavel {
default void desenhar() {
//
}
}
C#
public static class MyExtensions {
public static int ExtensionMethod(this ClassToBeExtended str) {
//
}
}
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
trait HasArea {
fn area(&self) -> f64;
}
impl HasArea for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
Go
// Se uma struct possui todos os métodos
// listados na interface, ele automaticamente
// implementa uma interface sem precisar
// declarar explicitamente
import (
"math"
)
type HasArea interface {
Area() float64
}
type Circle struct {
radius float64
}
func (c *Circle) Area() float64 {
return math.Pi * (c.radius * c.radius)
}
C++
// use herança múltipla
Objective-C
@protocol A
- (NSInteger)requiredMethod;
- (NSInteger)anotherRequiredMethod;
@property (nonatomic, assign) NSInteger aProp;
@optional
- (NSInteger)optionalMethod;
// required methods again
@required
- (NSInteger)requireMethodAfterOptional;
@end
@protocol B
//
@end
@protocol C <A>
//
@end
@protocol D <A, B>
//
@end
@interface : NSObject <C, D>
@synthesize aProp
@end
Swift
// public internal private
// interfaces
protocol P {
// pode conter variáveis e métodos
func someMethod() -> int
}
protocol Q {
//
}
// implementação default
// com extension methods
extension P { // where Element: Equatable { // podemos passar condições se precisar
func someMethod() -> {
return 1
}
}
// structs
struct S : P, Q {
// para structs, o padrão dos métodos
// é ser const
func constMethod() {
//
}
mutating func structMethod() {
//
}
}
final class D : C, P, Q {
override init() {
super.init()
}
init?() {
return nil
}
convenience init() {
//
}
// o override pode ser mais visível!
override internal func myMethod() {
super.myMethod()
}
}
let o2 = D()
Kotlin
interface A {
fun foo() { print("A") }
fun bar()
val prop:Int // abstract
val propertyWithImplementation:String
get() = "foo"
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
interface I : B {
//
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
// se as interfaces tiverem
// implementações default
// de métodos com a mesma assinatura
// é obrigatório redefiní-lo na classe
override fun bar() {
super<B>.bar()
}
}
Java
interface A {
// método estático
static public int someStaticMethod() {
return 1;
}
// método virtual
int someMethod();
}
interface B {
// método virtual
int someOtherMethod();
// método default
// é sempre público também
// java 8+
default int anotherMethod() {
return 1;
}
}
class C implements A, B {
// se as interfaces tiverem
// implementações default
// de métodos com a mesma assinatura
// é obrigatório redefiní-lo na classe
}
C#
interface IA {
// método estático
static public int someStaticMethod() {
return 1;
}
// método virtual
int someMethod();
}
interface IB {
// método virtual
int someOtherMethod();
// método default
// c# 8+
int anotherMethod() {
return 1;
}
// TODO interfaces agora podem
// ter métodos e pripriedades
// private, protected, etc...
}
class C : IA, IB {
// se as interfaces tiverem
// implementações default
// de métodos com a mesma assinatura
// é obrigatório redefiní-lo na classe
}
Dart
TypeScript
JavaScript
-ActionScript
Python
-PHP
VBA / VB6 IA.cls
[File: IA.cls, Instancing: PublicNotCreatable]
Option Explicit
Public Property Get Name() As String
End Property
VBA / VB6 - C.cls
[File: C.cls, Instancing: Private]
Option Explicit
Implements IA
Private m_name As String
Private Sub Class_Initialize()
m_name = ""
End Sub
Public Property Get Name() As String
Name = m_name
End Property
VBA / VB6 - Module.bas
[File: Module1.bas]
Option Explicit
Public Sub TestInterface()
Dim someObject As New C
someObject.Name = "John"
End Sub
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
trait Foo {
fn foo(&self);
}
trait Bar {
fn bar(&self);
}
trait FooBar : Foo + Bar {
fn foobar(&self);
}
Go
// não suporta herança,
// mas tem um atalho para composição
C++
class A {
//
}
class B : A {
//
}
class C : A {
//
}
// herança múltipla
// usar herança virtual para diminuir
// problemas com ambiguidade
class D final : B, C {
// super
}
Objective-C
@interface A : NSObject
//
@end
@interface B : A
// super
@end
Swift
class C {
static func myStaticMethod() {
//
}
static var myStaticProp:S
init() {
//
}
deinit {
//
}
private func myMethod() {
self.prop
}
var getter:S {
return ...
}
var getterSetter:S {
get {
return self._getterSetter
}
set(newValue) { // ou newValue implícito set {
self._getterSetter = newValue
}
}
lazy var prop:S
private _getterSetter:S
// setter pode ser menos visível que o getter
public private(set) var numberOfEdits = 0
// internal
private(set) var numberOfEdits = 0
}
final class R : C {
required init() {
// super
}
}
let o1 = C()
let o2 = D()
Kotlin
open class A() {
//
}
class B() : A() {
// super
}
Java
class A {
//
}
final class B extends A {
// super
}
sealed class C permits D {
//
}
final class D extends C {
//
}
C#
class A {
//
}
sealed class B : A {
// base
}
Dart
TypeScript
JavaScript
class A {
//
}
class B extends A {
constructor() {
super(); // TODO verificar
Object.seal(this);
}
}
// ou
let a = {};
let b = Object.create(a, {});
ActionScript
Python
class A:
class B(A):
class C(A):
# herança múltipla
# veja C3 para resolução
# de métodos com mesma assinatura
class D(B, C):
pass # super()
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Rust
-Go
-C++
class AbstractClass {
// virtual e =0 fazem essa função ser puramente virtual
// o que torna a classe abstrata
virtual void AbstractMemberFunction() = 0;
// uma classe abstrata ainda pode conter outros tipos de métodos
// e atributos
virtual void NonAbstractMemberFunction1(); // Virtual function.
void NonAbstractMemberFunction2();
};
Objective-C
-Swift
-Kotlin
abstract class A {
//
}
// uma classe abstrata pode ser inserida
// no meio de uma cadeia de herança
open class B {
open fun someMethod() {}
}
abstract class C : B() {
abstract override fun someMethod()
}
Java
abstract class A {
//
}
C#
abstract class A {
//
}
Dart
TypeScript
JavaScript
-ActionScript
Python
from abc import ABC
class AbstractBaseClass(ABC):
pass
# ou
class AbstractBaseClass(ABC):
@abstractmethod
def my_abstract_method(self, ...):
#
@property
@abstractmethod
def my_abstract_property(self):
#
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
A
Rust
-Go
-C++
-Objective-C
-Swift
-Kotlin
public final class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState:Bundle?) {
super.onCreate(savedInstanceState)
this.txtValorMes!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s:CharSequence, start:Int, count:Int, after:Int) { /**/}
override fun onTextChanged(s:CharSequence, start:Int, before:Int, count:Int) {
// this@ acessa o escopo nomeado
this@MainActivity.mainProperty
}
override fun afterTextChanged(s:Editable) { /**/ }
})
}
private var mainProperty:Int
}
Java
public final class MainActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
this.txtValorMes.addTextChangedListener(new TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { /**/ }
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Container.this acessa o escopo externo
Container.this.mainProperty;
}
@Override
public void afterTextChanged(Editable s) { /**/ }
})
}
private int mainProperty;
}
C#
// C# tem anonymus types
// que só podem ter atributos e nada mais
Dart
TypeScript
JavaScript
// JavaScript não tem classes
// apenas objetos
// Objetos anônimos podem
// ser criados facilmente
// com a sintaxe {}
ActionScript
Python
# ver https://docs.python.org/3/library/types.html
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
// ver "trait objects" na doc oficial
Go
C++
Objective-C
// dynamic dispatch
Swift
// static e dynamic dispatch
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
pub struct Generica<T> {
// valor padrão para T é Default::default()
propriedadeGenerica: T
}
Go
-C++
template <class T>
class Generica final {
T propriedadeGenerica;
}
Objective-C
@interface Generica<__covariant ObjectType> : NSObject
@property (assign, nonatomic) ObjectType propriedadGenerica;
@end
@interface HerdaDeU<__covariant ObjectType:U *> : NSObject
@end
// TODO __contravariant tb pode ser usado?
// usa type erasure :(
Swift
public final class Generica<T> {
// TODO qual é o valor padrão de T?
private T propriedadeGenerica// = [Element]()
}
public final class Generica2Tipos<T, U> {
//
}
public final class HerdaDeU<T : U> {
//
}
public final class Restricoes<T : U> where T.Item == U.Item {
//
}
Kotlin
public class Generica<T>() {
//
}
// TODO ver where, in e out
// usa type erasure :(
Java
public final class Generica<T> {
// valor padrão para T é null
private T propriedadeGenerica = null;
}
Generica gen1 = new Generica<Integer>();
public final class Generica2Tipos<T, U> {
//
}
Generica2Tipos gen2 = new Generica2Tipos<Integer, Float>();
public final class HerdaDeU<T extends U> {
//
}
public final class RegrasCombinadas<T extends U & V> {
//
}
public final class Coringa<?> {
// ou wildcard, permite qquer coisa
}
public final class CoringaTipado<? extends Number> {
// pois Generica<Integer> não herda de Generica<Number>
// mas o wild card CoringaTipado<? extends Number>
// permite CoringaTipado<Integer>
}
// usa type erasure, permitindo bugs com casts etc.
C#
public sealed class Generica<T> {
// valor padrão para T é default(T)
private T propriedadeGenerica = default(T);
}
var gen1 = new Generica<int>();
public sealed class Generica2Tipos<T, U> {
//
}
var gen2 = new Generica2Tipos<int, float>();
public sealed class SoValueType<T> where T : struct {
//
}
var gen3 = new SoValueType<int>();
public sealed class SoReferenceType<T> where T : class {
//
}
var gen4 = new SoReferenceType<object>();
public sealed class PossuiConstrutorPublicoPadrao<T> where T : new() {
//
}
public sealed class HerdaDeU<T> where T : U {
//
}
public sealed class RegrasCombinadas<T> where T : U, V, new() {
//
}
Dart
TypeScript
JavaScript
// tipagem dinâmica
ActionScript
Python
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S', int, str)
class StrangePair(Generic[T, S]):
#
from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust - main.rs
mod MusicNote;
mod Enumerators;
use Enumerators::Step;
use Enumerators::Semitone;
fn main() {
let mut musicNote = MusicNote::MusicNote {
step: Step::Do,
semitone: Default::default()
};
musicNote = musicNote + Semitone::Sharp;
println!("{}", musicNote); // Do♯
}
Rust - MusicNote.rs
use std::ops::Add;
use std::fmt;
use Enumerators::Step;
use Enumerators::Semitone;
pub struct MusicNote {
/*pub Step Step {
get;
private set;
}
pub Semitone Semitone {
get;
set;
}*/
pub step:Step,
pub semitone:Semitone
}
impl Add<Semitone> for MusicNote {
type Output = MusicNote;
fn add(self, rightHandSide:Semitone) -> MusicNote {
if rightHandSide == Semitone::None {
return self;
}
let mut newStep = self.step;
let mut newSemitone = rightHandSide;
if newSemitone == Semitone::Sharp
&& (newStep == Step::Mi || newStep == Step::E)
{
newStep = Step::Fa;
newSemitone = Semitone::None;
} else if newSemitone == Semitone::Flat
&& (newStep == Step::Fa || newStep == Step::F)
{
newStep = Step::Mi;
newSemitone = Semitone::None;
}
// Rest of add logic here
return MusicNote { step: newStep, semitone: newSemitone }
}
}
impl fmt::Display for MusicNote {
fn fmt(&self, formatter:&mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{}{}", self.step, self.semitone)
}
}
Rust - Enumerators.rs
use std::default::Default;
use std::fmt;
// Rust não permite que uma mesma literal
// seja atribuído a dois valores diferentes
// Do = 1, C = 1
#[derive(PartialEq, Eq)]
pub enum Step {
// solfèje
Do,
Re,
Mi,
Fa,
Sol,
La,
Si,
// abc
C,
D,
E,
F,
G,
A,
B
}
impl fmt::Display for Step {
fn fmt(&self, formatter:&mut fmt::Formatter) -> fmt::Result {
match *self {
Step::Do | Step::C => write!(formatter, "Do"),
Step::Re | Step::D => write!(formatter, "Re"),
Step::Mi | Step::E => write!(formatter, "Mi"),
Step::Fa | Step::F => write!(formatter, "Fa"),
Step::Sol | Step::G => write!(formatter, "Sol"),
Step::La | Step::A => write!(formatter, "La"),
Step::Si | Step::B => write!(formatter, "Si")
}
}
}
#[derive(PartialEq, Eq)]
pub enum Semitone {
None = 127,
Natural = 0,
DoubleFlat = -2,
Flat = -1,
Sharp = 1,
DoubleSharp = 2
}
impl Default for Semitone {
fn default() -> Semitone { Semitone::None }
}
impl fmt::Display for Semitone {
fn fmt(&self, formatter:&mut fmt::Formatter) -> fmt::Result {
match *self {
Semitone::None => write!(formatter, ""),
Semitone::Natural => write!(formatter, "♮"),
Semitone::DoubleFlat => write!(formatter, "𝄫"),
Semitone::Flat => write!(formatter, "♭"),
Semitone::Sharp => write!(formatter, "♯"),
Semitone::DoubleSharp => write!(formatter, "𝄪")
}
}
}
Go
-C++ - main.cpp
#include <iostream>
#include "MusicNote.hpp"
int main(int argc, const char* argv[]) {
using std::cout;
using std::endl;
using MarcoLuglio::OpOvExample::MusicNote;
using MarcoLuglio::OpOvExample::Step;
using MarcoLuglio::OpOvExample::Semitone;
auto cSharp = MusicNote(Step::C, Semitone::None);
cSharp = cSharp + Semitone::Sharp;
cout << cSharp << endl; // Do♯
auto note1 = MusicNote(Step::C);
cout << note1++ << endl; // Do
auto note2 = MusicNote(Step::C);
cout << ++note2 << endl; // Do♯
return 0;
}
C++ - MusicNote.hpp
#pragma once
#include <cstdint>
#include <string>
#include "Enumerators.hpp"
namespace MarcoLuglio {
namespace ThreadExample {
class MusicNote final {
public:
MusicNote(Step step, Semitone semitone = Semitone::None);
// Não é possível declarar operator<< como
// um membro da classe. Mas podemos declará-lo
// como uma friend function, que consegue acessar
// as propriedades privadas da classe como se
// fosse um membro
friend std::ostream& operator<<(
std::ostream& os,
const MusicNote& obj
);
MusicNote operator+(const Semitone semitone) const;
/// prefix increment
MusicNote& operator++();
/// postfix increment
MusicNote operator++(int);
Step getStep();
Semitone getSemitone();
private:
Step step;
Semitone semitone;
};
}
}
C++ - MusicNote.cpp
#include "MusicNote.hpp"
namespace MarcoLuglio {
namespace ThreadExample {
using std::string;
MusicNote::MusicNote(Step step, Semitone semitone)
: step{step}, semitone{semitone} {
//
}
MusicNote MusicNote::operator+(const Semitone semitone) const {
if (semitone == Semitone::None) {
return *this;
}
Step newStep = this->step;
Semitone newSemitone = semitone;
if (newSemitone == Semitone::Sharp
&& (newStep == Step::Mi || newStep == Step::E)
) {
newStep = Step::Fa;
newSemitone = Semitone::None;
} else if (newSemitone == Semitone::Flat
&& (newStep == Step::Fa || newStep == Step::F)
) {
newStep = Step::Mi;
newSemitone = Semitone::None;
}
// Rest of add logic here
return MusicNote(newStep, newSemitone);
}
MusicNote& MusicNote::operator++() {
MusicNote& ref = *this;
auto tmp = ref + Semitone::Sharp;
this->step = tmp.getStep();
this->semitone = tmp.getSemitone();
return ref;
}
MusicNote MusicNote::operator++(int) {
MusicNote tmp{*this}; // copy
this->operator++(); // pre-increment
return tmp; // return old value
}
Step MusicNote::getStep() {
return this->step;
}
Semitone MusicNote::getSemitone() {
return this->semitone;
}
std::ostream& operator<<(
std::ostream& os,
const MusicNote& note
) {
os << note.step << note.semitone;
return os;
}
}
}
C++ - Enumerators.hpp
#pragma once
namespace MarcoLuglio {
namespace OpOvExample {
enum Step : uint8_t {
// solfèje
Do = 1,
Re = 3,
Mi = 5,
Fa = 6,
Sol = 8,
La = 10,
Si = 12,
// abc
C = 1,
D = 3,
E = 5,
F = 6,
G = 8,
A = 10,
B = 12
};
enum Semitone : int8_t {
None = 127,
Natural = 0,
DoubleFlat = -2,
Flat = -1,
Sharp = 1,
DoubleSharp = 2
};
std::ostream& operator<<(std::ostream& os, const Step& step);
std::ostream& operator<<(std::ostream& os, const Semitone& semitone);
}
}
C++ - Enumerators.cpp
#include "Enumerators.hpp"
namespace MarcoLuglio {
namespace OpOvExample {
std::ostream& operator<<(
std::ostream& os,
const Step& step
) {
switch (step) {
case Step::Do:
os << "Do";
break;
case Step::Re:
os << "Re";
break;
case Step::Mi:
os << "Mi";
break;
case Step::Fa:
os << "Fa";
break;
case Step::Sol:
os << "Sol";
break;
case Step::La:
os << "La";
break;
case Step::Si:
os << "Si";
break;
default:
break;
}
return os;
}
std::ostream& operator<<(
std::ostream& os,
const Semitone& semitone
) {
switch (semitone) {
case Semitone::None:
break;
case Semitone::Natural:
os << "♮";
break;
case Semitone::DoubleFlat:
os << "𝄫";
break;
case Semitone::Flat:
os << "♭";
break;
case Semitone::Sharp:
os << "♯";
break;
case Semitone::DoubleSharp:
os << "𝄪";
break;
default:
break;
}
return os;
}
}
}
Objective-C
-Swift - main.swift
var musicNote = MusicNote(step: Step.do, semitone: Semitone.none)
musicNote = musicNote + Semitone.sharp
print(musicNote) // Do♯
Swift - MusicNote.swift
public final class MusicNote : CustomStringConvertible {
init(step:Step, semitone:Semitone = Semitone.none) {
self.step = step
self.semitone = semitone
}
public var description:String {
return "\(self.step)\(self.semitone)"
}
public fileprivate(set) var step = Step.do
public var semitone = Semitone.none
}
// posso fazer isso estático tb dentro da classe MusicNote
func + (left:MusicNote, right:Semitone) -> MusicNote {
if right == Semitone.none {
return left
}
var newStep:Step = left.step
var newSemitone:Semitone = right
if newSemitone == Semitone.sharp
&& (newStep == Step.mi || newStep == Step.e)
{
newStep = Step.fa
newSemitone = Semitone.none
} else if newSemitone == Semitone.flat
&& (newStep == Step.fa || newStep == Step.f)
{
newStep = Step.mi;
newSemitone = Semitone.none;
}
// Rest of add logic here
return MusicNote(step: newStep, semitone: newSemitone)
}
Swift - Enumerators.swift
// Rust não permite que uma mesma literal
// seja atribuído a dois valores diferentes
// `do` = 1, c = 1
public enum Step : UInt8, CustomStringConvertible {
// solfèje
case `do`
case re
case mi
case fa
case sol
case la
case si
// abc
case c
case d
case e
case f
case g
case a
case b
public var description:String {
switch self {
case .do, .c:
return "Do"
case .re, .d:
return "Reo"
case .mi, .e:
return "Mi"
case .fa, .f:
return "Fa"
case .sol, .g:
return "Sol"
case .la, .a:
return "La"
case .si, .b:
return "Si"
}
}
}
public enum Semitone : Int8, CustomStringConvertible {
case none = 127
case natural = 0
case doubleFlat = -2
case flat = -1
case sharp = 1
case doubleSharp = 2
public var description:String {
switch self {
case .none:
return ""
case .natural:
return "♮"
case .doubleFlat:
return "𝄫"
case .flat:
return "♭"
case .sharp:
return "♯"
case .doubleSharp:
return "𝄪"
}
}
}
Kotlin - main.kt
fun main(args: Array<String>) {
//
}
Kotlin - MusicNote.kt
public final class MusicNote {
//
}
operator fun MusicNote.inc():MusicNote {
//
}
operator fun MusicNote.plus(semitone:Semitone) {
//
}
Kotlin - Semitone.kt
Java
-C# - MainClass.cs
using System;
namespace MarcoLuglio.OpOvExample {
public class MainClass {
public static void Main(string[] args) {
// Sim, de onde você achava que tinha vindo??
var cSharp = new MusicNote(Step.C, Semitone.None);
cSharp = cSharp + Semitone.Sharp;
Console.WriteLine(cSharp); // Do♯
var note1 = new MusicNote(Step.C);
Console.WriteLine(note1++); // Do
var note2 = new MusicNote(Step.C);
Console.WriteLine(++note2); // Do♯
}
}
}
C# - MusicNote.cs
using System;
namespace MarcoLuglio.OpOvExample {
public sealed class MusicNote {
public static MusicNote operator +(MusicNote note, Semitone semitone) {
if (semitone == Semitone.None) {
return note;
}
Step newStep = note.step;
Semitone newSemitone = semitone;
if (newSemitone == Semitone.Sharp
&& (newStep == Step.Mi || newStep == Step.E)
) {
newStep = Step.Fa;
newSemitone = Semitone.None;
} else if (newSemitone == Semitone.Flat
&& (newStep == Step.Fa || newStep == Step.F)
) {
newStep = Step.Mi;
newSemitone = Semitone.None;
}
// Rest of add logic here
return new MusicNote(newStep, newSemitone);
}
public static MusicNote operator ++(MusicNote note) {
// Retorne sempre um novo objeto dentro desse override
// Para que que o prefixo e o sufixo ++ funcionem corretamente
// Nesse caso o override do + irá se encarregar disso
return note + Semitone.Sharp;
}
public MusicNote(Step step, Semitone semitone = Semitone.None) {
this.Step = step;
this.Semitone = semitone;
}
public override string ToString() {
return string.Format("{0}{1}", Step, Semitone.ToDescriptionString());
}
public Step Step {
get;
private set;
}
public Semitone Semitone {
get;
set;
}
private Step step = Step.Do;
private Semitone semitone = Semitone.None;
}
}
C# - Enumerators.cs
using System;
using System.ComponentModel; // Description attribute
namespace MarcoLuglio.OpOvExample {
public enum Step : byte {
// solfèje
Do = 1,
Re = 3,
Mi = 5,
Fa = 6,
Sol = 8,
La = 10,
Si = 12,
// abc
C = 1,
D = 3,
E = 5,
F = 6,
G = 8,
A = 10,
B = 12
}
public enum Semitone : sbyte {
[Description("")]
None = 0,
[Description("♮")]
Natural = 0,
[Description("\uD834\uDD2B")]
DoubleFlat = -2,
[Description("♭")]
Flat = -1,
[Description("♯")]
Sharp = 1,
[Description("\uD834\uDD2A")]
DoubleSharp = 2
}
public static class SemitoneExtensions {
public static string ToDescriptionString(this Semitone semitone) {
DescriptionAttribute[] attributes = (DescriptionAttribute[])semitone
.GetType()
.GetField(semitone.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
}
}
Dart
// https://dart.dev/guides/language/language-tour#methods
TypeScript
-JavaScript
// https://github.com/tc39/proposal-operator-overloading
ActionScript
Python - main.py
#
Python - MusicNote.py
class MusicNote:
#
Python - Semitone.py
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust - OpOvCollection.rs
use std::ops::Index;
use std::ops::IndexMut;
use std::default::Default;
pub struct OpOvCollection<T> where T:Default {
pub array:[T; 10]
}
// pode ser indexada por inteiros
impl<T> Index<usize> for OpOvCollection<T> where T:Default {
type Output = T;
fn index(&self, index:usize) -> &T {
&self.array[index]
}
}
// pode ser indexada por inteiros
impl<T> IndexMut<usize> for OpOvCollection<T> where T:Default {
fn index_mut<'a>(&'a mut self, index:usize) -> &'a mut T {
&mut self.array[index]
}
}
// ou por outros tipos
// TODO
impl<T> Default for OpOvCollection<T> where T:Default {
fn default() -> OpOvCollection<T> {
OpOvCollection::<T> {
array: Default::default()
}
}
}
Rust - main.rs
let mut opOvCollection:OpOvCollection::OpOvCollection<str> = Default::default();
opOvCollection[0] = "sunday";
opOvCollection[1] = "monday I'm in love";
opOvCollection[2] = "tuesday and wednesday too";
println!("{}", opOvCollection[2]);
Go
-C++ - OpOvCollection.hpp
#pragma once
#include <string>
namespace MarcoLuglio {
namespace IndexerExample {
using std::size_t;
using std::string;
using std::to_string;
/// type alias para simplificar a sintaxe
/// do retorno da função getArray
using arrayReference = int[10];
class OpOvCollection final {
public:
/// Classe auxiliar que permite alteração
/// dos valores da coleção
class Proxy final {
public:
Proxy(OpOvCollection& collection, const size_t index)
: collection{collection}, index{index} {}
/// Overload do operador = para alteração
/// dos valores da coleção
int& operator= (int newValue) {
collection.array[index] = newValue;
return collection.array[index]; // FIXME
}
/// C++ não possui uma classe base comum
/// então as conversões para string devem ser
/// implementadas sempre
operator string() const {
return to_string(collection.array[index]);
}
private:
/// Referência da coleção original, para alteracão
/// dos valores nos índices
OpOvCollection &collection;
size_t index;
};
OpOvCollection();
/// Overload do operador [] para obtenção
/// dos valores da coleção
/// Esse overload só possibilita retornar valores,
/// portanto é necessário que ele retorne um objeto
/// proxy ao invés do valor real, pois o proxy
/// possibilita a alteração do valor na coleção
/// original
OpOvCollection::Proxy operator[](const size_t index);
private:
/// Coleção original
int array[10];
}
}
}
C++ - OpOvCollection.cpp
#include "OpOvCollection.hpp"
namespace MarcoLuglio {
namespace IndexerExample {
using CollectionProxy = OpOvCollection::Proxy;
using std::size_t;
/// type alias para simplificar a sintaxe
/// do retorno da função getArray
using arrayReference = int[10];
OpOvCollection::OpOvCollection() {
// inicia a array com valores 0
std::fill(this->array, this->array + 9, 0);
}
CollectionProxy OpOvCollection::operator[](const size_t index) {
return CollectionProxy(*this, index);
}
}
}
C++ - main.cpp
#include <iostream>
#include <string>
#include "OpOvCollection.hpp"
int main(int argc, const char* argv[]) {
using std::cout;
using std::endl;
using std::string;
using MarcoLuglio::IndexerExample::OpOvCollection;
auto opOvCollection = OpOvCollection();
opOvCollection[0] = 7;
opOvCollection[1] = 45;
opOvCollection[2] = 83;
string value = (string)opOvCollection[2];
// 83
cout << value << endl;
return 0;
}
Objective-C - IndexedCollection.h
@interface {
}
// pode ser indexada por inteiros
- (id) objectAtIndexedSubscript:(int)index;
- (void) setObject:(id)obj atIndexedSubscript:(int)index;
// ou por outros tipos
- (id) objectForKeyedSubscript:(NSString)key;
- (void) setObject:(id)obj forKeyedSubscript:(NSString)key;
@end
Objective-C - IndexedCollection.m
#import "IndexedCollection.h"
@implementation
// TODO
@end
Objective-C - main.m
#import "IndexedCollection.h"
int main(int argc, const char* argv[]) {
IndexedCollection* indexedCollection = [IndexedCollection new];
indexedCollection[0] = "sunday";
indexedCollection[1] = "monday I'm in love";
indexedCollection[2] = "tuesday and wednesday too";
// "tuesday and wednesday too"
NSLog(indexedCollection["tuesday"]);
return 0;
}
Swift - SubscriptCollection.swift
// Swift não tem valores padrão para tipos, nem tem uma classe base comum
// Então usamos um protocolo que o tipo genérico deve seguir
public final class SubscriptCollection<T:StringLiteralConvertible> {
init() {
self.array = [T](count:10, repeatedValue:"")
}
// pode ser indexada por inteiros
subscript(index:Int) -> T {
get {
return self.array[index]
}
set(newValue) {
self.array[index] = newValue
}
}
// ou por outros tipos
subscript(key:String) -> T {
get {
var string:String
var stringStart:String
var stringIndex:String.Index
for item in self.array {
string = String(item)
if string.isEmpty || string == "nil" {
continue
}
stringIndex = string.startIndex.advancedBy(key.count)
stringStart = string.substringToIndex(stringIndex)
if stringStart == key {
return item
}
}
// retorna uma string vazia se não encontrar um item pela chave
// já que o tipo deve poder ser convertido para string
return ""
}
}
// e ainda por mais de um índice
subscript(key:String, index:Int) -> T {
get {
var string:String
var stringStart:String
var stringIndex:String.Index
var currentIndex = 0
for item in self.array {
string = String(item)
if string.isEmpty || string == "nil" {
continue
}
stringIndex = string.startIndex.advancedBy(key.count)
stringStart = string.substringToIndex(stringIndex)
if stringStart == key {
if currentIndex == index {
return item
} else {
currentIndex = currentIndex + 1
}
}
}
return ""
}
}
var array:Array<T>
}
Swift - main.swift
var subscriptCollection = SubscriptCollection<String>()
subscriptCollection[0] = "sundays are slow";
subscriptCollection[1] = "mondays are mediocre";
subscriptCollection[2] = "tuesday and wednesday too";
subscriptCollection[3] = "monday again";
// "tuesday and wednesday too"
print(subscriptCollection["tuesday"]);
// "monday again"
print(subscriptCollection["monday", 1]);
Kotlin - IndexedCollection.kt
class Point(val x:Int, val y:Int)
operator fun Point.get(i) = Point(-x, -y)
val point = Point(10, 20)
fun main() {
println(-point) // prints "Point(x=-10, y=-20)"
}
// TODO implementar operador get conforme abaixo
/*
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ..., i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ..., i_n] = b a.set(i_1, ..., i_n, b)
*/
Kotlin - main.kt
Java
-C# - IndexedCollection.cs
namespace MarcoLuglio.IndexerExample {
public sealed class IndexedCollection<T> {
public IndexedCollection() {
this.array = new T[10];
}
// pode ser indexada por inteiros
public T this[int index] {
get {
return this.array [index];
}
set {
this.array [index] = value;
}
}
// ou por outros tipos
public T this[string key] {
get {
foreach(var item in this.array) {
if (item.ToString().StartsWith(key)) {
return item;
}
}
// retorna valor padrão para o tipo
// se não encontrar um item pela chave
return default(T);
}
}
private T[] array;
}
}
C# - MainClass.cs
using System;
namespace MarcoLuglio.IndexerExample {
public class MainClass {
public static void Main(string[] args) {
var indexedCollection = new IndexedCollection<string>();
indexedCollection[0] = @"sunday";
indexedCollection[1] = @"monday I'm in love";
indexedCollection[2] = @"tuesday and wednesday too";
// "tuesday and wednesday too"
Console.WriteLine(indexedCollection[@"tuesday"]);
}
}
}
Dart
class Test {
Map data = {
"a": 1,
"b": 2
};
operator [](index) => data[index];
operator []=(index, value) { data[index] = value; }
}
TypeScript
JavaScript
'use strict';
const indexingProxy = {
get(alvo, propriedade, receiver) {
// pode ser indexada por inteiros
if (/^\d+$/.test(propriedade)) {
return Reflect.get(alvo._array, propriedade, receiver);
}
// ou por outros tipos
for (let valor of alvo._array) {
if (valor.startsWith(propriedade)) {
return valor;
}
}
// retorna null
// se não encontrar um item pela chave
return null;
},
set(alvo, propriedade, valor, receiver) {
// pode ser indexada por inteiros
if (/^\d+$/.test(propriedade)) {
alvo._array[propriedade] = valor;
return true;
}
// ou por outros tipos
alvo._array.push(valor);
return true;
}
};
class Collection {
constructor() {
Object.defineProperty(this, '_array', {value: []});
}
}
const collection = new Collection();
const indexedCollection = new Proxy(collection, indexingProxy);
indexedCollection[0] = "sunday";
indexedCollection[1] = "monday I'm in love";
indexedCollection[2] = "tuesday and wednesday too";
// "tuesday and wednesday too"
console.log(indexedCollection["tuesday"]);
ActionScript
Python
# implementar object.__getitem__(self, key)
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
C# possibilita a criação de indexers de maneira relativamente simples. Swift requer passos extras devido ao fato de que não existe uma maneira rápida de obter o valor padrão de um tipo genérico, mas isso é compensado pelo fato de que é simples utilizar mais de um índice com o operador []
.
JavaScript não diferencia os operadores .
e []
, mas se os utilizarmos ingenuamente, deixaremos o código lento, criando propriedades nos objetos em tempo de execução. Por isso o uso de um Proxy
se faz necessário.
C++ Também requer um proxy, mas por outros motivos. O operador []
em C++ só retorna valores, então devemos retornar um proxy que possui uma referência para a posição desejada na coleção original, e por meio dele alterar o valor nessa posição. Para que isso seja possível, o proxy também deve ter alguns overloads de operadores, tornando tudo mais verborrágico e complicado do que nas outras linguagens.
Rust
// use procedural macros
// TODO
#[proc_macro_attribute]
pub fn show_streams(
attr: TokenStream,
item: TokenStream
) -> TokenStream {
println!("attr: \"{}\"", attr.to_string());
println!("item: \"{}\"", item.to_string());
item
}
#[show_streams(bar)]
fn invoke2() {}
Go
package main
import (
"fmt"
"reflect"
)
type T struct {
f1 string "f one"
f2 string
f3 string `f three`
f4, f5 int64 `f four and five`
f6 string `one:"1" two:"2"blank:""`
}
func main() {
t := reflect.TypeOf(T{})
f1, _ := t.FieldByName("f1")
fmt.Println(f1.Tag) // f one
f4, _ := t.FieldByName("f4")
fmt.Println(f4.Tag) // f four and five
f5, _ := t.FieldByName("f5")
fmt.Println(f5.Tag) // f four and five
f6, _ := t.FieldByName("f6")
fmt.Println(f6.Tag) // one:"1" two:"2"blank:""
v, ok := f6.Tag.Lookup("one")
fmt.Printf("%s, %t\n", v, ok) // 1, true
v, ok = f6.Tag.Lookup("blank")
fmt.Printf("%s, %t\n", v, ok) // , true
v, ok = f6.Tag.Lookup("five")
fmt.Printf("%s, %t\n", v, ok) // , false
}
C++
-Objective-C
// não permite atributos customizados
// apenas pré-definidos
Swift
// não permite atributos customizados
// apenas pré-definidos
Kotlin
@Target(AnnotationTarget.CLASS)
annotation class AClassAnnotation(val aParam:String)
@Target(AnnotationTarget.FUNCTION)
annotation class AMethodAnnotation(val aParam:String)
@AClassAnnotation("metadata about class")
class AnnotatedClass {
@AMethodAnnotation("metadata about class")
void AnnotatedMethod() {
//
}
}
val aClassAnnotation = AnnotatedClass::class
.annotations
.find { it is AClassAnnotation } as? AClassAnnotation
println(AClassAnnotation?.aParam)
Java
@Target(ElementType.CLASS)
@Retention(RetentionPolicy.RUNTIME)
public @interface AClassAnnotation {
public String aParam() default "";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AMethodAnnotation {
public String aParam() default "";
}
@AClassAnnotation(aParam = "metadata about class")
class AnnotatedClass {
@AMethodAnnotation(aParam = "metadata about class")
void AnnotatedMethod() {
//
}
}
AClassAnnotation aClassAnnotation = obj
.getClass()
.getAnnotation(AClassAnnotation.class);
if (aClassAnnotation != null) {
String aParam = aClassAnnotation.aParam();
}
C#
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AClassAttribute : Attribute {
public AClassAttribute(string aParam) {
//
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class AMethodAttribute : Attribute {
public AMethodAttribute(string aParam) {
//
}
}
[AClassAttribute("metadata about class")]
public sealed class AnnotatedClass {
[AMethodAttribute("metadata about method")]
public void AnnotatedMethod() {
...
}
}
var annotatedClassType = typeof(AnnotatedClass);
var aClassAttribute = (AClassAttribute) Attribute.GetCustomAttribute(
annotatedClassType,
typeof (AClassAttribute)
);
Dart
class AnAnnotation {
final String name;
final String description;
const Todo(this.name, this.description);
}
@AnAnnotation('Chibi', 'Rename class')
class AnnotatedClass {
@AnAnnotation('Tuwaise', 'Change fielld type')
int annotatedValue;
}
AnnotatedClass annotatedClass = new AnnotatedClass();
InstanceMirror im = reflect(annotatedClass);
ClassMirror classMirror = im.type;
classMirror.metadata.forEach((metadata) {
if (metadata.reflectee is Todo) {
print(metadata.reflectee.name);
print(metadata.reflectee.description);
}
});
for (var v in classMirror.declarations.values) {
if (!v.metadata.isEmpty) {
if (v.metadata.first.reflectee is Todo) {
print(v.metadata.first.reflectee.name);
print(v.metadata.first.reflectee.description);
}
}
}
TypeScript
JavaScript
// acompanhe essa feature
ActionScript
package {
import flash.display.Sprite;
// pure .as file projects accepted metadata for the stage settings
[SWF(width="1024", height="768", backgroundColor='#405050', frameRate="60")]
public class MainStage extends Sprite {
public function MainStage() {
stage.quality = StageQuality.HIGH;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
super();
}
}
}
Python
def a_class_decorator(cls):
class NewClass(cls):
attr = 100
return NewClass
@a_class_decorator
class X:
pass
def a_function_decorator(aParam, func):
def wrapper():
print("Do something")
func()
return wrapper
@a_function_decorator("a param")
def say_whee():
print("Whee!")
#####################################
import functools
class state_decorator:
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@state_decorator
def say_whee():
print("Whee!")
PHP
VBA / VB6
-Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
A
Rust - TabelaNutricional.rs
#[repr(C)]
pub struct TabelaNutricional {
valorEnergetico:f32,
carboidratos:f32,
proteinas:f32,
gordurasTotais:f32,
gordurasSaturadas:f32,
gordurasTrans:f32,
fibraAlimentar:f32,
sodio:f32
}
#[no_mangle]
pub extern "C" fn calcular(porcao:f32) -> TabelaNutricional {
let mut tabela = TabelaNutricional{
valorEnergetico: 1_f32,
carboidratos: 1_f32,
proteinas: 1_f32,
gordurasTotais: 1_f32,
gordurasSaturadas: 1_f32,
gordurasTrans: 1_f32,
fibraAlimentar: 1_f32,
sodio: 2_f32
};
// TODO usar porcao
return tabela;
}
// compilar com
// rustc --crate-type dylib TabelaNutricional.rs
// vai gerar libTabelaNutricional.dylib
/*
Calling conventons válidas:
stdcall
aapcs
cdecl
fastcall
Rust
rust-intrinsic
system
C
win64
sysv64
*/
Go
// compile using -buildmode=c-shared
// go build -o nutricao.so -buildmode=c-shared nutricao.go
C++ - TabelaNutricional.hpp
#pragma once
#ifdef __cplusplus
namespace MarcoLuglio {
namespace FFIExample {
extern "C" {
#endif
struct TabelaNutricional {
float valorEnergetico;
float carboidratos;
float proteinas;
float gordurasTotais;
float gordurasSaturadas;
float gordurasTrans;
float fibraAlimentar;
float sodio;
};
#ifdef __cplusplus
}
}
}
#endif
C++ - TabelaNutricional.cpp
#include "TabelaNutricional.hpp"
namespace MarcoLuglio {
namespace FFIExample {
// TODO ver se esse arquivo
// é realmente necessário
}
}
C++ - TabelaNutricionalBiblioteca.hpp
#pragma once
#ifdef _MSC_VER // Visual Studio specific macro
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __attribute__((visibility("default")))
#endif
#include "TabelaNutricional.hpp"
#ifdef __cplusplus
namespace MarcoLuglio {
namespace FFIExample {
extern "C" {
#endif
DLLEXPORT struct TabelaNutricional calcular(float porcao);
#ifdef __cplusplus
}
}
}
#endif
C++ - TabelaNutricionalBibliteca.cpp
#include "TabelaNutricional.hpp"
#include "TabelaNutricionalBibliteca.hpp"
namespace MarcoLuglio {
namespace FFIExample {
TabelaNutricional calcular(const float porcao) {
TabelaNutricional tabela{};
// ...
return tabela;
}
}
}
Objective-C
-Swift
-Kotlin
-Java
-C#
-Dart
-TypeScript
-JavaScript
-ActionScript
-Python
-PHP
-VBA / VB6
' ??
Ada - Nutricao.ads
-- usar pragma Convention e Export
with Interfaces.C;
package Nutricao is
type TabelaNutricional is
record
ValorEnergetico:Interfaces.C.C_float;
Carboidratos:Interfaces.C.C_float;
Proteinas:Interfaces.C.C_float;
GordurasTotais:Interfaces.C.C_float;
GordurasSaturadas:Interfaces.C.C_float;
GordurasTrans:Interfaces.C.C_float;
FibraAlimentar:Interfaces.C.C_float;
Sodio:Interfaces.C.C_float;
end record;
pragma Convention (
Convention => C,
Entity => TabelaNutricional
);
function Calcular(Porcao:Float) return TabelaNutricional;
pragma Export (C, Calcular, "calcular");
end Nutricao;
Nutricao.adb
package body Nutricao is
function Calcular(Porcao:Float) return TabelaNutricional is
begin
-- return ...;
end Calcular;
end Nutricao;
Object Pascal (Delphi)
type TObj = object
private
Caption:ShortString;
public
constructor init;
destructor done;
procedure SetCaption(AValue:String);
function GetCaption:String;
end;
type point = record
X,Y,Z:Real;
end;
type RPoint = record
case Boolean of
False: (X,Y,Z:Real);
True: (R,theta,phi:Real);
end;
type BetterRPoint = record
case UsePolar:Boolean of
False: (X,Y,Z:Real);
True: (R,theta,phi:Real);
end;
function Calcular(Porcao:Single):TabelaNutricional; cdecl;
begin
// return ...;
end;
{
Calling conventons válidas:
register
pascal
cdecl
stdcall
safecall
winapi
}
Ruby
Smalltalk
Common Lisp
Haskell
Rust
#[repr(C)]
pub struct TabelaNutricional {
valorEnergetico:f32,
carboidratos:f32,
proteinas:f32,
gordurasTotais:f32,
gordurasSaturadas:f32,
gordurasTrans:f32,
fibraAlimentar:f32,
sodio:f32
}
#[link(name = "TabelaNutricionalBiblioteca")]
extern "C" {
fn calcular(porcao:f32) -> TabelaNutricional;
}
fn main() {
unsafe {
calcular(20);
}
}
Go
// CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS e LDFLAGS
// podem ajustar o comportamento das bibliotecas C
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// ou podemos usar pkg-config
// #cgo pkg-config: png cairo
// #include <png.h>
import "C"
// When the Go tool sees that one or more Go files use the special import "C",
// it will look for other non-Go files in the directory and compile them
// as part of the Go package.
// Any .c, .s, .S or .sx files will be compiled with the C compiler.
// Any .cc, .cpp, or .cxx files will be compiled with the C++ compiler.
// Any .f, .F, .for or .f90 files will be compiled with the fortran compiler.
// Any .h, .hh, .hpp, or .hxx files will not be compiled separately,
// but, if these header files are changed, the package (including its non-Go
// source files) will be recompiled.
// mais detalhes na documentação oficial
C++
// usar LoadLibrary/GetProcAddress/FreeLibrary no Windows
// ou dlopen/dlsym/dlclose no Mac e Linux
// ou linkar as bibliotecas em tempo de compilação
// ou adicionar as referências nas IDEs respectivas
Objective-C
// Objective-C é um superset de C
// portanto pode incluir cabeçalhos
// chamar funções e usar structs C
// normalmente
Swift
// XCode cria um bridging header
// quando inserimos arquivos C
Kotlin
// Somente Kotlin native?
// import kotlinx.cinterop.*
Java - TabelaNutricional.java
package marcoLuglio.ffiExample;
public final class TabelaNutricional {
public float valorEnergetico;
public float carboidratos;
public float proteinas;
public float gordurasTotais;
public float gordurasSaturadas;
public float gordurasTrans;
public float fibraAlimentar;
public float sodio;
}
Java - TabelaNutricionalBibliotecaNative.java
package marcoLuglio.ffiExample;
public final class TabelaNutricionalBibliotecaNative {
static {System.loadLibrary("TabelaNutricionalBiblioteca");}
private native TabelaNutricional calcular(float porcao);
}
// Also JNI
// And look a new API proposal https://openjdk.java.net/jeps/412
C# - TabelaNutricionalBibliotecaNative.cs
// Adicionar a referência ao arquivo na IDE e:
using System.Runtime.InteropServices;
namespace MarcoLuglio.FFIExample {
[StructLayout(LayoutKind.Sequential)]
public struct TabelaNutricional {
public float valorEnergetico;
public float carboidratos;
public float proteinas;
public float gordurasTotais;
public float gordurasSaturadas;
public float gordurasTrans;
public float fibraAlimentar;
public float sodio;
};
public static class SalarioBibliotecaNative {
[DllImport(
"TabelaNutricionalBiblioteca.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = @"calcular"
)]
public static extern TabelaNutricional calcular(float porcao);
}
}
Dart
import 'dart:ffi'
show DynamicLibrary, NativeFunction, Int32;
main() {
final lib = DynamicLibrary.open('TabelaNutricionalBiblioteca.dylib');
final TabelaNutricional Function(double porcao) calcular = lib
.lookup<NativeFunction<Int32 Function(Int32, Int32)>>('calcular')
.asFunction();
// calcular(1);
}
TypeScript
JavaScript
// No navegador não existe, mas veja
// Web Assembly
// Já usando node.js veja o plug-in FFI
ActionScript
// calls a host function
flash.external.ExternalInterface.call('calcular', 1);
// then the host needs to interface with c
Python
import ctypes
TabelaNutricionalBiblioteca_dll = ctypes.cdll.LoadLibrary('TabelaNutricionalBiblioteca.dll')
TabelaNutricionalBiblioteca_dll.calcular(1)
PHP
$ffi = FFI::load(__DIR__ . '/TabelaNutricionalBiblioteca.h');
// or
$ffi = FFI::cdef(
'struct TabelaNutricional {
float valorEnergetico;
float carboidratos;
float proteinas;
float gordurasTotais;
float gordurasSaturadas;
float gordurasTrans;
float fibraAlimentar;
float sodio;
};
TabelaNutricional calcular(float porcao);',
'TabelaNutricionalBiblioteca.so' // or 'libc.so.6'??
);
$ffi->calcular(1);
VBA / VB6
Declare Function calcular Lib "C:\pathto\TabelaNutricionalBiblioteca.dll" (ByVal porcao As Double) As TabelaNutricional
Ada
with Interfaces.C; use Interfaces.C;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type TabelaNutricional is record
valorEnergetico:float;
carboidratos:float;
proteinas:float;
gordurasTotais:float;
gordurasSaturadas:float;
gordurasTrans:float;
fibraAlimentar:float;
sodio:float;
end record
with Convention => C;
function calcular(porcao:float) return TabelaNutricional
with Import => True, Convention => C;
tabelaNutricional:TabelaNutricional;
begin
tabelaNutricional := calcular (2);
end Main;
Object Pascal (Delphi)
procedure calcular; external 'TabelaNutricionalBiblioteca.dll';
// or
procedure calcular; external 'TabelaNutricionalBiblioteca.dll' delayed;
// or
var
lLibraryHandle:THandle;
lCalcular:procedure; stdcall;
begin
lLibraryHandle := LoadLibrary('TabelaNutricionalBiblioteca.dll');
if lLibraryHandle <= 32 then begin // 32 magic constant for success
lCalcular := GetProcAddress(lLibraryHandle, 'calcular');
lCalcular();
FreeLibrary(lLibraryHandle);
end;
end;
Ruby
require 'ffi'
module LibC
extend FFI::Library
ffi_lib FFI::Platform::LIBC
attach_function :strdup, [:string], :pointer
attach_function :free, [:pointer], :void
end
string = "Hello, World!"
duplicate = LibC.strdup(string)
puts duplicate.get_string(0)
LibC.free(duplicate)
Smalltalk
DLD addLibrary: 'TabelaNutricionalBiblioteca'.
Object subclass: ExtLib [
ExtLib class >> openimage: aString [
(CFunctionDescriptor isFunction: 'openimage')
ifTrue: [
(CFunctionDescriptor for: 'openimage'
returning: #int
withArgs: #(#string)
) callInto: (ValueHolder null).
] ifFalse: [ ('internal open image %1' % { aString }) displayNl ]
]
].
ExtLib calcular: 1.
Common Lisp
(cffi:load-foreign-library "TabelaNutricionalBiblioteca.so")
(cffi:foreign-funcall "calcular"
:string #+sbcl (sb-posix:getenv "DISPLAY")
#-sbcl ":0.0"
:pointer
)
Haskell
C++ e Rust são os únicos que conseguem exportar bibliotecas compatíveis com C, por se tratarem de linguagens nativas. C++ Possui grande preocupação com a compatibilidade com C, e pode misturar de maneira transparente blocos de código em C.
As bibliotecas geradas por Rust são enormes se comparados com as do C++, para comportar as regras da linguagem.
Objective-C é construído tendo C como base. Portanto, assim como C++, pode usar C de maneira transparente. Só não pode exportar para C :(
Swift?? TODO
C# possui uma sintaxe limpa para interagir com APIs em C
Java pode até ser bonitinho dentro do arquivo Java, mas o arquivo C que interage com ele é bastante complexo. Tanto que foram criadas ferramentas que geram parte deste arquivo automaticamente.
JavaScript ainda não chegou lá.
Rust
Go
// https://medium.com/learning-the-go-programming-language/writing-modular-go-programs-with-plugins-ec46381ee1a9
C++
Objective-C
Swift
Kotlin
Java
C#
// https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support
Dart
// https://flutter.dev/docs/development/packages-and-plugins/developing-packages
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A
Rust - server.rs - actix framework
// actix uses tokio for async .await
use actix_web::{web, App, HttpRequest, HttpServer, Responder};
#[get("/")]
async fn index(_req:HttpRequest) -> impl Responder {
"Hello from the index page!"
}
async fn greet(req:HttpRequest) -> impl Responder {
let name = req.match_info().get("name").unwrap_or("World");
format!("Hello {}!", &name)
}
#[actix_web::main]
async fn main() -> Result<()> {
HttpServer::new(|| {
App::new()
.service(index)
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Rust - server.rs
use std::fs;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
fn main() {
// TODO handle SIGINT, SIGTERM, etc.
println!("Starting go server on port 80");
// containers must use 0.0.0.0! localhost or 127.0.0.1 do not work!
let listener = TcpListener::bind("0.0.0.0:80");
match listener {
Ok(result) => {
// TODO match here too
listen_incoming_connections(result);
},
Err(err) => println!("{}", err)
}
}
fn listen_incoming_connections(listener:TcpListener) -> Result<(), std::io::Error> {
for stream in listener.incoming() {
handle_connection(stream?)?;
}
Ok(())
}
fn handle_connection(mut stream:TcpStream) -> Result<usize, std::io::Error> {
let mut buffer = [0; 1024];
let buffer_result = stream.read(&mut buffer)?; // TODO implement timeouts
// formato das requisições
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
// methods and root uri
let options = b"OPTIONS / ";
let get = b"GET / ";
if buffer.starts_with(options) {
handle_options(buffer, stream)?;
} else if buffer.starts_with(get) {
handle_get(buffer, stream)?;
} else {
println!("TODO 404")
/*(
"HTTP/1.1 404 NOT FOUND",
"content-type: text/html".to_string(),
"404.html"
)*/
};
Ok(buffer_result)
}
// formato das respostas
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
fn handle_options(buffer:[u8; 1024], mut stream:TcpStream) -> Result<(), std::io::Error> {
let (status_line, headers) = (
"HTTP/1.1 200 OK",
concat!(
"access-control-allow-origin: *", // posso usar *, mas não se requerir autenticação com bearer:
"access-control-allow-methods: options, get, post, put, delete",
"access-control-allow-headers: content-type", // posso usar *
)
.to_string()
);
let response = format!("{}\r\n{}", status_line, headers);
// TODO implement timeouts
stream.write(response.as_bytes())?;
stream.flush()?;
Ok(())
}
fn handle_get(buffer:[u8; 1024], mut stream:TcpStream) -> Result<(), std::io::Error> {
let (status_line, mut headers, filename) = (
"HTTP/1.1 200 OK",
"content-type: application/json".to_string(),
"hello.json"
);
let body = fs::read_to_string(filename)?;
headers = [
headers,
"\r\ncontent-length: ".to_string(),
body.len().to_string()
]
.concat();
let response = format!("{}\r\n{}\r\n\r\n{}", status_line, headers, body);
// TODO implement timeouts
stream.write(response.as_bytes())?;
stream.flush()?;
Ok(())
}
Rust - client.rs - ureq crate
fn main() -> Result<(), ureq::Error> {
let body: String = ureq::get("http://example.com")
.set("Example-Header", "header value")
.call()?
.into_string()?;
Ok(())
}
Rust - client.rs - reqwest crate
let body = reqwest::get("https://www.rust-lang.org")
.await?
.text()
.await?;
Go - server.go
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
fmt.Println("Starting go server on port 80")
handler := timeoutHandler{}
timeoutServer := &http.Server{
ReadHeaderTimeout: 20 * time.Second,
ReadTimeout: 1 * time.Minute,
WriteTimeout: 2 * time.Minute,
Handler: handler,
Addr: ":80",
}
timeoutServer.ListenAndServe()
}
// #region timeoutHandler struct
type timeoutHandler struct{}
func (handler timeoutHandler) ServeHTTP(
responseWriter http.ResponseWriter,
request *http.Request
) {
defer request.Body.Close()
switch request.RequestURI {
case "/":
// OK
default:
// TODO 404
return
}
/*
// this is how to do a varible timeout to read the request
// but it will also eat part of the write timeout
timer := time.AfterFunc(5*time.Second, func() {
request.Body.Close()
})
// if more time is needed to write the response
// reset the timer here, os in another method
timer.Reset(1 * time.Second)
*/
var err error
switch request.Method {
case "OPTIONS":
err = handleOptions(responseWriter, request)
case "GET":
err = handleGet(responseWriter, request)
}
if err != nil {
// util.CheckError(err)
// return
}
}
// #endregion
func handleOptions(
responseWriter http.ResponseWriter,
request *http.Request
) (err error) {
// posso usar *, mas não se requerir autenticação com bearer:
responseWriter.Header().Set(
"access-control-allow-origin",
"*"
)
responseWriter.Header().Set(
"access-control-allow-methods",
"options, get, post, put, delete"
)
// posso usar *
responseWriter.Header().Set(
"access-control-allow-headers",
"content-type"
)
return
}
func handleGet(
responseWriter http.ResponseWriter,
request *http.Request
) (err error) {
responseWriter.Header().Set(
"content-type",
"application/json"
)
responseWriter.WriteHeader(200)
responseWriter.Write([]byte(`{"hello":"world"}`))
return
}
Go - client.go
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
resp, err := http.Get("http://example.com/")
resp, err := http.Post(
"http://example.com/upload",
"image/jpeg", &buf
)
resp, err := http.PostForm(
"http://example.com/form",
url.Values{"key": {"Value"}, "id": {"123"}}
)
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
}
C++
Objective-C
Swift - client.swift
let url = URL(string: "http://www.stackoverflow.com")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
task.resume()
Kotlin
// Spring Boot
Java
C# - server
// Use the Asp.Net templates
C# - client.cs
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://example.com");
// httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await httpClient.GetAsync("/someResource");
// TODO maybe there's a faster way to check for success
// without throwing exceptions?
// response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
string responseString = String.Empty;
using (var reader = new System.IO.StreamReader(responseStream, Encoding.UTF8)) {
responseString = await reader.ReadToEndAsync();
}
Dart
// https://dart.dev/server
// https://github.com/subfuzion/dart-flutter-fullstack-demo/blob/main/backend/bin/server.dart
TypeScript
JavaScript - server.mjs - nodejs
import http from 'http';
//create a server object:
http.createServer(function (req, res) {
res.write('Hello World!');
res.end();
}).listen(8080);
// or with express https://expressjs.com/en/starter/hello-world.html
// https://expressjs.com/en/advanced/best-practice-performance.html
JavaScript - client.js
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
Assembly
A
Protocol Buffer definition
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
// then run protoc for the given language
Rust
// no official one yet
Go - server.go
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
Go - client.go
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
C++
Objective-C
Swift
// check apple documentation
Kotlin
Java
C# - server
public sealed class GreeterImpl : Greeter.GreeterBase
{
// Server side handler of the SayHello RPC
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
// Server side handler for the SayHelloAgain RPC
public override Task<HelloReply> SayHelloAgain(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = "Hello again " + request.Name });
}
}
C# - client
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
var client = new Greeter.GreeterClient(channel);
String user = "you";
var reply = client.SayHello(new HelloRequest { Name = user });
Console.WriteLine("Greeting: " + reply.Message);
var secondReply = client.SayHelloAgain(new HelloRequest { Name = user });
Console.WriteLine("Greeting: " + secondReply.Message);
channel.ShutdownAsync().Wait();
Dart
TypeScript
JavaScript
ActionScript
-Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust
Go
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/graphql-go/graphql"
)
func main() {
// Schema
fields := graphql.Fields {
// resolver for hello
"hello": &graphql.Field {
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return "world", nil
},
},
}
rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields}
schemaConfig := graphql.SchemaConfig{ Query: graphql.NewObject(rootQuery) }
schema, err := graphql.NewSchema(schemaConfig)
if err != nil {
log.Fatalf("failed to create new schema, error: %v", err)
}
// Query
query := `
{
hello
}
`
params := graphql.Params{Schema: schema, RequestString: query}
r := graphql.Do(params)
if len(r.Errors) > 0 {
log.Fatalf("failed to execute graphql operation, errors: %+v", r.Errors)
}
rJSON, _ := json.Marshal(r)
fmt.Printf("%s \n", rJSON) // {"data":{"hello":"world"}}
}
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust - Cargo.toml
tokio-tungstenite = "0.12.0"
Rust - server.rs
use std::net::TcpListener;
//use tungstenite::server::accept;
use tokio_tungstenite::accept_async;
#[tokio::main]
async fn main() {
let server = TcpListener::bind("127.0.0.1:9001").unwrap();
// let size = 5;
// let mut workers = Vec::with_capacity(size);
for stream in server.incoming() {
let worker = tokio::spawn(async move {
let mut websocket = accept_async(stream.unwrap())
.await
.unwrap();
loop {
let msg = match websocket.read_message().await {
// socket closed
Ok(msg) if msg == 0 => return,
// We do not want to send back ping/pong messages
Ok(msg) if msg.is_binary() || msg.is_text() => msg, // websocket.write_message(msg).unwrap();
//Ok(msg) => msg,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return;
}
};
}
});
// workers.push(worker);
}
/*
// close all sockets
for _ in &workers {
let _ = sender.send(Message::Terminate);
}
// wait for the close message to be acknoledged
for worker in workers {
let _ = worker.await;
}
*/
}
Go - gorilla library
// great article comparing alternatives
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader {
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil) // error ignored for sake of simplicity
for {
// Read message from browser
msgType, msg, err := conn.ReadMessage()
if err != nil {
return
}
// Print the message to the console
fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))
// Write message back to browser
if err = conn.WriteMessage(msgType, msg); err != nil {
return
}
}
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "websockets.html")
})
http.ListenAndServe(":8080", nil)
}
C++
Objective-C
Swift - server.swift
// https://github.com/apple/swift-nio/blob/main/Sources/NIOWebSocketServer/main.swift
Swift - client.swift
// https://developer.apple.com/documentation/foundation/urlsessionwebsockettask
// or cross platform
// https://github.com/apple/swift-nio/blob/main/Sources/NIOWebSocketClient/main.swift
Kotlin
// use java libraries
import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import org.json.JSONException
import org.json.JSONObject
import java.lang.Exception
import java.net.URI
import javax.net.ssl.SSLSocketFactory
private lateinit var webSocketClient:WebSocketClient
override fun onCreate(savedInstanceState:Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
initWebSocket()
}
override fun onPause() {
super.onPause()
webSocketClient.close()
}
private fun initWebSocket() {
val coinbaseUri:URI? = URI("wss://ab.com")
createWebSocketClient(coinbaseUri)
}
private fun createWebSocketClient(coinbaseUri:URI?) {
webSocketClient = object : WebSocketClient(coinbaseUri) {
override fun onOpen(handshakedata:ServerHandshake?) {
subscribe()
}
override fun onMessage(message: tring?) {
setUpBtcPriceText(message)
}
override fun onClose(code:Int, reason:String?, remote:Boolean) {
unsubscribe()
}
override fun onError(ex:Exception?) {
// ex?.message
}
}
}
private fun subscribe() {
webSocketClient.send(
// json string here
)
}
// use https://square.github.io/okhttp/
// use https://ktor.io/docs/creating-web-socket-chat.html
Java
C#
// https://marcoluglio.github.io/br/tutorialwebsockets/
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-5.0
Dart
// https://api.dart.dev/stable/2.13.1/dart-io/WebSocket-class.html
final channel = WebSocketChannel.connect(
Uri.parse('wss://echo.websocket.org'),
);
StreamBuilder(
stream: channel.stream,
builder: (context, snapshot) {
return Text(snapshot.hasData ? '${snapshot.data}' : '');
},
)
channel.sink.add('Hello!');
channel.sink.close();
TypeScript
JavaScript
const socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
A
Rust - server.rs
Rust - client.rs
Go - server.go
package main
import (
"log"
"net"
)
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
_, err = c.Write(data)
if err != nil {
log.Fatal("Write: ", err)
}
}
}
func main() {
l, err := net.Listen("unix", "/tmp/echo.sock")
if err != nil {
log.Fatal("listen error:", err)
}
for {
fd, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
go echoServer(fd)
}
}
Go - client.go
package main
import (
"io"
"log"
"net"
"time"
)
func reader(r io.Reader) {
buf := make([]byte, 1024)
for {
n, err := r.Read(buf[:])
if err != nil {
return
}
println("Client got:", string(buf[0:n]))
}
}
func main() {
c, err := net.Dial("unix", "/tmp/echo.sock")
if err != nil {
panic(err)
}
defer c.Close()
go reader(c)
for {
_, err := c.Write([]byte("hi"))
if err != nil {
log.Fatal("write error:", err)
break
}
time.Sleep(1e9)
}
}
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
// https://api.dart.dev/stable/2.13.1/dart-io/Socket-class.html
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
LLVM IR
Assembly
A
Rust
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 1, y: 2 };
// Convert the Point to a JSON string.
let serialized = serde_json::to_string(&point).unwrap();
// Prints serialized = {"x":1,"y":2}
println!("serialized = {}", serialized);
// Convert the JSON string back to a Point.
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
// Prints deserialized = Point { x: 1, y: 2 }
println!("deserialized = {:?}", deserialized);
}
Go
package main
import (
"encoding/json"
"fmt"
"os"
)
type response1 struct {
Page int
Fruits []string
}
type response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
func main() {
mapD := map[string]int { "apple": 5, "lettuce": 7 }
mapB, _ := json.Marshal(mapD)
fmt.Println(string(mapB))
res1D := &response1 {
Page: 1,
Fruits: []string { "apple", "peach", "pear" }
}
res1B, _ := json.Marshal(res1D)
fmt.Println(string(res1B))
byt := []byte(`{ "num":6.13,"strs":["a","b"] }`)
var dat map[string]interface{}
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
num := dat["num"].(float64)
fmt.Println(num)
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
str := `{ "page": 1, "fruits": ["apple", "peach"] }`
res := response2 {}
json.Unmarshal([]byte(str), &res)
fmt.Println(res)
fmt.Println(res.Fruits[0])
enc := json.NewEncoder(os.Stdout)
d := map[string]int { "apple": 5, "lettuce": 7 }
enc.Encode(d)
}
C++
// use an external library
Objective-C
Swift
import Foundation
let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"
let data = Data(str.utf8)
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let dictionary = jsonWithObjectRoot as? [String: Any] {
if let number = dictionary["someKey"] as? Double {
// access individual value in dictionary
}
for (key, value) in dictionary {
// access all key / value pairs in dictionary
}
if let nestedDictionary = dictionary["anotherKey"] as? [String: Any] {
// access nested dictionary values by key
}
}
if let array = jsonWithArrayRoot as? [Any] {
if let firstObject = array.first {
// access individual object in array
}
for object in array {
// access all objects in array
}
for case let string as String in array {
// access only string values in array
}
}
// we need to manually map the dictionary to a struct
struct Restaurant {
enum Meal: String {
case breakfast, lunch, dinner
}
let name: String
let location: (latitude: Double, longitude: Double)
let meals: Set<Meal>
}
extension Restaurant {
init(json: [String: Any]) throws {
// Extract name
guard let name = json["name"] as? String else {
throw SerializationError.missing("name")
}
// Extract and validate coordinates
guard let coordinatesJSON = json["coordinates"] as? [String: Double],
let latitude = coordinatesJSON["lat"],
let longitude = coordinatesJSON["lng"]
else {
throw SerializationError.missing("coordinates")
}
let coordinates = (latitude, longitude)
guard case (-90...90, -180...180) = coordinates else {
throw SerializationError.invalid("coordinates", coordinates)
}
// Extract and validate meals
guard let mealsJSON = json["meals"] as? [String] else {
throw SerializationError.missing("meals")
}
var meals: Set<Meal> = []
for string in mealsJSON {
guard let meal = Meal(rawValue: string) else {
throw SerializationError.invalid("meals", string)
}
meals.insert(meal)
}
// Initialize properties
self.name = name
self.coordinates = coordinates
self.meals = meals
}
}
Kotlin
import kotlinx.serialization.json
//...
@Serializable
data class User(val name:String, val yearOfBirth:Int)
val data = User("Louis", 1901)
val string = Json.encodeToString(data)
println(string) // {"name":"Louis","yearOfBirth":1901}
val obj = Json.decodeFromString(string)
// val obj = Json.parse(User.serializer(), string)
println(obj) // User(name=Louis, yearOfBirth=1901)
Java
C#
using System.Text.Json;
public sealed class CsEntity {
public string Id { get; set; } = String.Empty;
public IEnumerable<OtherCsEntity>? OtherProp { get; set; }
}
var jsonSerializerOptions = new JsonSerializerOptions {
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
IncludeFields = true
};
var fromJson = await JsonSerializer
.DeserializeAsync<CsEntity>(
responseString,
jsonSerializerOptions
);
var fromJsonList = JsonSerializer
.Deserialize<IEnumerable<CsEntity>>(
responseString,
jsonSerializerOptions
);
Dart
// https://dart.dev/guides/json
// using json_serializable package
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
User(this.name, this.email);
String name;
String email;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
Map<String, dynamic> userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);
// using
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:built_collection/built_collection.dart';
part 'person.g.dart';
abstract class Person implements Built<Person, PersonBuilder> {
static Serializer<Person> get serializer => _$personSerializer;
// Can never be null.
int get id;
@nullable
int get age;
@nullable
@BuiltValueField(wireName: 'first_name')
String get firstName;
@nullable
BuiltList<String> get hobbies;
Person._();
factory Person([void Function(PersonBuilder) updates]) = _$Person;
}
// TODO
TypeScript
const fromJson:SomeType = JSON.parse('{ "a": "b" }');
JavaScript
const fromJson = JSON.parse('{ "a": "b" }');
ActionScript
Python
import json
toJson = {
"a": "b"
}
jsonString = json.dumps(x)
# no native direct mapping...
parsedTuples = json.loads(jsonString)
PHP
$json = '{"foo-bar": 12345}';
$obj = json_decode($json);
print $obj->{'foo-bar'};
VBA / VB6
# use external library
Ada
with Ada.Text_IO;
with GNATCOLL.JSON;
procedure JSON_Test is
use Ada.Text_IO;
use GNATCOLL.JSON;
JSON_String:constant String := "{""name"":""Pingu"",""born"":1986}";
Penguin:JSON_Value := Create_Object;
Parents:JSON_Array;
begin
Penguin.Set_Field(
Field_Name => "name",
Field => "Linux"
);
Penguin.Set_Field(
Field_Name => "born",
Field => 1992
);
Append(Parents, Create("Linus Torvalds"));
Append(Parents, Create("Alan Cox"));
Append(Parents, Create("Greg Kroah-Hartman"));
Penguin.Set_Field(
Field_Name => "parents",
Field => Parents
);
Put_Line(Penguin.Write);
Penguin := Read(JSON_String, "json.errors");
Penguin.Set_Field(
Field_Name => "born",
Field => 1986
);
Parents := Empty_Array;
Append(Parents, Create("Otmar Gutmann"));
Append(Parents, Create("Silvio Mazzola"));
Penguin.Set_Field(
Field_Name => "parents",
Field => Parents
);
Put_Line (Penguin.Write);
end JSON_Test;
Object Pascal (Delphi)
uses System.JSON;
procedure ParseJSonValue;
var
JSonValue:TJSonValue;
st:String;
Branch:String;
begin
st := '{"data":{"results":[{"Branch":"ACCT590003"}]}}';
JsonValue := TJSonObject.ParseJSONValue(st);
Branch := JsonValue.GetValue('data.results[0].Branch');
JsonValue.Free;
end;
// embarcadero has 2 more libraries to work with
// http://docwiki.embarcadero.com/RADStudio/Sydney/en/JSON
Ruby
require 'json'
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source, {object_class: OpenStruct})
json = '["foo", 1, 1.0, 2.0e2, true, false, null]'
ruby = JSON.parse(json)
json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}'
ruby = JSON.parse(json)
Smalltalk
Common Lisp
Haskell
A
Rust
Go
C++
Objective-C
Swift
Kotlin
Java
C#
Dart
TypeScript
JavaScript
ActionScript
Python
PHP
VBA / VB6
Ada
Object Pascal (Delphi)
Ruby
Smalltalk
Common Lisp
Haskell
Web Assembly text format
LLVM IR
Assembly
A