Profile cover photo
Profile photo
Yuri Albuquerque
390 followers -
Todas as coisas criadas estão sujeitas à decadência. Atinja a liberação se esforçando com diligência.
Todas as coisas criadas estão sujeitas à decadência. Atinja a liberação se esforçando com diligência.

390 followers
About
Communities and Collections
View all
Posts

Post has attachment
RESSUCITEI O BLOG
Sinto muito, mas GURPS não é bom
Sinto muito, mas GURPS não é bom
adeptodoheroismo.blogspot.com
Add a comment...

Post has attachment

Post has attachment
Add a comment...

Post has shared content

Post has attachment
Você vai votar na primeira opção?
-
votes visible to Public
100%
Não
0%
Sim
Add a comment...

Post has attachment
Photo
Add a comment...

Falando um pouco mais sobre Rust, agora vou explicar como Rust consegue implementar segurança de memória sem precisar de mecanismos de runtime como um garbage collector (dessa forma sendo potencialmente tão rápido quanto C ou C++).

Rust tem três tipos de ponteiros: owned pointers (também chamados "boxes"), borrowed pointers ("references") e raw pointers (iguais aos ponteiros do C. Só podem ser usados dentro de blocos unsafe).

A linguagem em si formaliza o conceito de "ownership", então um objeto é propriedade da variável que o contém. Quando ocorre passagem de parâmetro, atribuição ou retorno de função, o objeto é copiado (com shallow copy) para a outra variável.

O ponto de diferença é que para objetos com algum conceito de ownership (como owned pointers, ou structs e enums que contenham owned pointers) a propriedade do objeto vai ser movida para a próxima variável após uma shallow copy.

Por exemplo:
    let x = ~1; //(~ é o símbolo que marca que aquela variável é um owned pointer, mais ou menos como o * em C)
    let y = x; /* o objeto de x foi movido para y */
    println!(x) /* erro de compilação. O objeto que "x" estava apontando foi movido para "y" */

Como você tem certeza absoluta de qual é a variável dona daquele objeto, assim que a variável sair de escopo, o destrutor do objeto será chamado!

Obviamente, nem sempre você vai querer mover o objeto. Você pode apenas querer tomá-lo emprestado numa função. E aí entram as references, ou borrowed pointers (indicados por &).

Uma reference tem a garantia em tempo de compilação de que a variável do tipo reference vai ter um lifetime menor do que a variável que está sendo apontada. Como assim?

    let y: ∫
    
    {
        let x = ~1;
        y = &(*x); // erro de compilação. O lifetime de "y" segue depois do de x
    }

Dessa forma, você pode emprestar variáveis sem medo de apontar para um null pointer ou um dangling pointer! De fato, null pointers só existem para raw pointers. Para ter um valor "opcional" (que pode ter algum valor ou valor nenhum), você usa o enum Option<T>.

Falando nisso, enums em Rust na verdade são algebraic data types, similares aos union types do Ceylon e do Kotlin.
Add a comment...

Post has attachment
O +Diego Coronel falou em promises com tipagem segura em Ceylon, o que me inspirou a falar um pouco sobre tasks em Rust.

Rust implementa concorrência com tasks, que são threads de usuário (em contrapartida com threads de kernel). O runtime da linguagem cria um pequeno conjunto de threads de kernel onde essas tasks vão rodar. Isso permite que várias tasks sejam disparadas com pouco overhead.

Apenas tendo tasks, contudo, não é o bastante para ter concorrência segura. Cada task de Rust é totalmente isolada, e só podem se comunicar entre si usando mensagens.

A maneira como Rust lida com mensagens é única devido ao seu sistema de tipos: como há um conceito de "owned pointers", além de ser possível passar uma variável numa mensagem por cópia, também é possível mover a variável de uma task para a outra. Como a variável é movida, a task que a continha originalmente não tem mais acesso a ela.

Dessa forma, é muito mais fácil lidar com concorrência sem se preocupar com os problemas comuns, já que acesso simultâneo a recursos se torna impossível, devido ao isolamento.

Criar uma biblioteca de actor model, similar ao que Erlang ou Scala fazem, também se torna mais fácil.

Caso seja necessário compartilhar dados imutáveis, contudo, existe a struct Arc (atomically reference counted) que permite isso com um nível de abstração simples.

Case realmente seja necessário compartilhar dados mutáveis, existe a RWArc, que é protegida por locks seguros (evitando problemas de nested mutexes).

Acho que seria interessante numa próxima vez falar um pouco sobre o sistema de ponteiros de Rust, que permite programas com segurança de memória sem precisar recorrer a um garbage collector.
Add a comment...

When will it be possible to change KDE's wallpaper through DBus? That's one killer feature that I miss A LOT in it.

My travel to the world of Rust never seem to stop amazing me.

First, there was the memory safety: no null pointers, no dangling pointers, no memory leaks. Not ever. No Garbage Collection to do that (although there is a std::gc::Gc structure for the specific use-cases where you can't run from a Garbage Collector, or std::rc::Rc if a reference counter solves your problem).

Then, there were the type system features: algebraic datatypes (disguised as Enums), linear types (owned and borrowed pointers, the things that make Rust memory-safe), tuples, struct tuples, traits, immutability by default (the way Ormagodden intended). While its type system is not as advanced as Haskell, Scala or ML (it still doesn't have higher kinded types, so I can't do something like Foo<T<U>>, or Foo<T> T<U>), it may absorb these concepts later own (higher kinded types are planned, but it's not a priority).

Then, object oriented features. They took a different approach on that: you create your structure like you would normally do (with a struct, or enum, or tuple, or tuple struct, or whatever), and then you create an "impl" block for it, where you define its methods. The impl block is also used for implement traits for your struct.

Then, functional features. There are, right now, copy closures and owned closures, besides being able to pass functions around just fine (but named functions are NOT closures). Unboxed closures (like those of C++) still don't exist, which is somewhat limiting. But it is predicted to be implemented.

And just yesterday I discovered its module system. Holy flying fuck, it is amazing.

As a comparison, in C++ I "include" my files, and I must compile every cpp in the project together somehow. Sometimes one cpp depends on the other, sometimes they depend on some external factor. This dependency stuff gets so complex that you need Makefiles to track them. And Makefiles are complex, so lots of build tools appeared to generate Makefiles, like autotools, cmake or qmake, only to name a few. These build toolchains get quite complex overtime.

Well, Rust does not need Makefiles.

You have modules in your application. You define which modules your application will have with the "mod" keyword. And then, you import symbols from these modules with the "use" keyword. This is unlike C++, C#, Java, or most popular languages, where you can only import modules (with   #include , using namespace, using or import), and you need to tell your build toolchain where to find them.

No, no. The mod keyword, when used (like "mod foo") will search its code either in foo/mod.rs or foo.rs (not both, that will give a compiler error). You can also inline your modules, or define another path if you really want (but this convention seems just fine). And then it does its magic of including your module into your compilation. So you only need to pass one file for the compiler, and it will inline the modules in that file (if you didn't make any mistakes, of course, like a circular dependency).

Besides that, modules can define that anything is public or private in it. You don't define that a given field of a struct is private, you define if it is private for that module. In other words, modules provides the encapsulation usually given by the object system itself.

The "use" keyword is also quite powerful. When you use it, Rust does not only search in the global module, it can also search relatively to your current module (like self::bar for a child module, or parent::baz for another child from the parent module).

And now another catch: when you use "extern mod", it searches for libraries. Yes, you don't need Makefiles, or maven, or gradle, or anything like it at all. You can define your whole dependency tree inside your code, in a sane manner.

And all of that in a systems language.

The developers must have sold their souls, it's impossible to have created such an well designed language otherwise.
Add a comment...
Wait while more posts are being loaded