hisham hm

🔗 How to write Lua modules in a post-module() world

Our beloved function module() is really going away. As of Lua 5.2 it’s only available with compatibility flags on, and the writing’s on the wall: it is going away for good in Lua 5.3. So, in a new Lua project I wrote this past semester, I decided to write it without using module(), while making sure my code runs on both Lua 5.1 and 5.2 (as a side result, I started the compat52 project, which allows you to write code in a well-behaved Lua 5.2 style and make it run on both 5.1 and 5.2).

So, why I liked module() in the first place? While vilified by some, I think the pros of module() largely trumped its cons. It had indeed some nice properties:

  • It provided much-needed policy for interoperability between modules - for the first time people were mostly writing Lua modules the same way and they worked with each other
  • It encouraged documenting the module name in its argument, which is especially useful in a world without clearly defined path policies. One would often find out where to put the module by looking at its name. Nevermind the ill-advised suggestion of writing module(...) “so that you can name the module whatever you want” — users of a module must agree on a name so that all other modules that need it can call require() properly!
  • It pushed modules that return a table through require() — while Lua’s mechanisms for modules were too lax and resulted in spilling globals too often, consistent use of module() meant that you could rely on writing local foo = require("foo"), which is “environmentally” clean idiom, albeit a bit repetitive.
  • You could nicely tell visibility through syntax: private functions declared with local function, public functions with function.
  • Apart from the awkward package.seeall argument, use of module() was pretty-much boilerplate-free (I hate repetition in code, from the ugly local print = print idioms in Lua to the redundancy of .h and .c files in C).

So, how to try to retain some of these properties without module()? The solution I found was to adopt some bits of policy, which I list below.

Yes, bits of policy. I know many in the Lua world hate policies, but of course I’m not putting a gun against anyone’s head to follow them. I’m only sharing what works for me and hopefully you may find some use. And don’t worry it’s nothing too esoteric, and it’s mostly cherry-picking some established practices.

Starting from the outside in

Keeping in mind that the goal of a module is to be required by client code, this is how a module foo.bar will be used:

local bar = require("foo.bar") -- requiring the module

bar.say("hello") -- using the module

An interesting observation here is that although we have a hierarchical structure of modules, the practice of loading them into locals means that in use they have to be accomodated in a flat namespace. So here’s Policy Bit #1:

Policy Bit #1: always require a module into a local named after the last component of the module’s full name.

Don’t do stuff such as local skt = require("socket") — code is much harder to read if we have to keep going back to the top to check how you chose to call a module.

Naming modules

Now that you know that your module will end up in people’s locals, please take that into consideration when naming your module. (I wish we had a capitalization policy to separate that nicely, but naming things LikeThis in Lua tends to be used only for object-oriented code.)

The idea is to choose a name that strikes a balance between convenience and uniqueness, and that is usable. And what better way to achieve this other than using this name. So, here’s Policy Bit #2, let’s use the module name in its declaration!

Policy Bit #2: start a module by declaring its table using the same all-lowercase local name that will be used to require it.

So, in the beginning of module foo.bar (which will live in foo/bar.lua), we begin with:

local bar = {}

It’s not a nice self-documenting header as we used to have with module("foo.bar", package.seall), but it’s something. We can improve that with LDoc comments:

--- @module foo.bar
local bar = {}

Don’t name your module something like “size”.

Declaring functions

When I’m scrolling through source code, I like to be able to tell what’s the sphere of influence of the piece of code I’m looking at. Is this a tiny helper function that’s only used below this line in this file? Is it an important function that’s used by other clients, so that an added or removed argument would mean API breakage? Ideally I like to be able to tell that without running back and forth in the code, so I really like visibility to be explicit in the syntax.

We must not declare global functions (or globals of any type, really!) in our modules, so using “globals vs. locals” to tell the difference won’t cut it. We have some alternatives, though. But first, let’s assert one thing:

Policy Bit #3: Use local function to declare local functions only: that is, functions that won’t be accessible from outside the module.

That is, local function helper_foo() means that helper_foo is really local.

This sounds obvious, but there are advocates of declaring all functions, public and private, as local functions and then writing an “export list” at the bottom of the module. Reading code written like this feels to me like a thriller with a twist ending: “haha, I was a public function all along!”

How to write public functions then? We must not declare global functions, but there are alternatives. Say we’re writing a function that will be used in client code as bar.say("hello"). It’s nice that we can declare it just like that:

function bar.say(greeting)
   print(greeting)
end

Policy Bit #4: public functions are declared in the module table, with dot syntax.

Visibility is made explicit through syntax. This is the same idea advocated by those who tell you to name your module tables “M”, except that you’re eating your own dogfood and using the name you expect your users to use. It’s also more consistent, since calls of say() are written bar.say() everywhere, instead of say(), M.say(), etc. (Also, “M.” looks really really ugly and people can’t decide if they want to use “M” or “_M”.)

In case you have speed concerns about having your calls go through the module table: first, this is what your users will go through; second, this is no different than using colon-syntax and dispatching through self and nobody complains about that; third, if you really need it (and have a benchmarked case for it), sure go ahead and make locals for optimization clearly marked as such; fourth, if you’re really after speed you’re probably using LuaJIT and last I heard the value of caching functions into locals is put into question there.

Classes and objects

When talking about classes and objects, it’s then time to talk about things named LikeThis. (If you don’t do OOP, feel free to skip this section!)

As we did above, let’s start look from the outside in: how to instantiate an object. There are two common practices (oh why I am not surprised :( )… you either make a class table with a “new” method, or make the “class object” callable (as a function or a table with a __call metamethod — wait, that makes it three practices…)

local myset1 = Set.new() -- style 1
local myset2 = Set() -- style 2.1 (set is a function)
local myset3 = Set() -- style 2.2 (set is a table)

If your module represents a class, I tend to like style 1 better because:

  • it keeps the invariant that modules are tables
  • it’s easy to store “static” methods as the other functions of the table
  • it’s less magic — I often run modules through for k,v in pairs(bar) do print(k,v) end in the interactive prompt to get a quick look of what they export.
  • it just screams “I’m creating an object”

If all your module does is define a class, I guess it makes sense to name the module file MyClass.lua and have the class table be the module table. But I prefer not to do that, because often what we store as “static” class methods in purely OOP languages are really module functions. I still use the uppercase table when implementing the class, like this:

--- @module myproject.myclass
local myclass = {}

-- class table
local MyClass = {}

function MyClass:some_method()
   -- code
end

function MyClass:another_one()
   self:some_method()
   -- more code
end

function myclass.new()
   local self = {}
   setmetatable(self, { __index = MyClass })
   return self
end

return myclass

It’s easy to see in the code above that the functions with MyClass in their signature are methods. Sometimes it’s nice to declare the functions as fields inside the table declaration, but declaring methods separately as in the example above allows you to keep local helper functions closer to where they’re used.

If all the module does is declare the class, the class and module table may be one and the same. If you want to use style 2, we get something like this:

--- @module myproject.MyClass
local MyClass = {}

function MyClass:some_method()
   -- code
end

function MyClass:another_one()
   self:some_method()
   -- more code
end

local metatable = {
   __call = function()
      local self = {}
      setmetatable(self, { __index = MyClass })
      return self
   end
}
setmetatable(MyClass, metatable)

return MyClass

Both methods are acceptable, as long as it’s easy and obvious to tell you’re doing OOP:

Policy Bit #5: construct a table for your class and name it LikeThis so we know your table is a class.

Policy Bit #6: functions that are supposed to be used as object methods should be clearly marked as such, and the colon syntax is a great way to do it.

Don’t make people reading your function have to guess (or look up) if it is a method, a public module function or a local function.

Wrapping up

Return the module table. It’s a bit of boilerplate, but it’s what we have to deal with in a module()less world:

return bar

Policy Bit #7: do not set any globals in your module and always return a table in the end.

To sum it all up, a complete module foo.bar would look like this:

--- @module foo.bar
local bar = {}

local function happy_greet(greeting)
   print(greeting.."!!!! :-D")
end

function bar.say(greeting)
   happy_greet(greeting)
end

return bar

The result is that we type a bit more than we did with module(), and we risk polluting the global namespace if we’re not careful, but with this set of policies, we have:

  • fairly self-documented code
  • visibility rules readable through syntax
  • modules that predictably return tables
  • as much consistency and as little boilerplate as possible

…which mostly matches what I liked about module(), to the extent that can be done without _ENV tricks.

I’ve been using these policies successfully in a university project, and my plan is to follow them when I update the LuaRocks codebase to drop the use of module(). Consider your self encouraged to adopt some or hopefully all of them, but most importantly, whatever you do, be consistent! Good luck in this brave post-module() world!

🔗 Micro-retrospectiva 2013

Da minha humilde meta de ler 12 livros por ano, esse ano consegui 7. As notícias boas são que é o melhor resultado dos últimos 3 anos, e que li pelo menos um livro em cada uma das quatro línguas que eu tento ler. (Além disso, tenho conseguido manter a média de ao menos uma HQ por ano). Aqui a lista atualizada.

en_US Coding places: software practice in a South American city - Yuri Takhteyev
fr_FR L’Étranger - Albert Camus
es_AR Ficciones - Jorge Luis Borges
pt_BR O crepúsculo dos ídolos, ou Como filosofar com o martelo - Friedrich Nietzsche
pt_BR Notas do subsolo - Fiódor Dostoiévski
pt_BR Toda poesia - Paulo Leminski
en_US The mythical man-month - Frederick Brooks

Esse foi um ano em que eu praticamente não encostei em instrumentos musicais (dos 365 dias não devo ter encostado em instrumentos mais do que… 20 dias?), o que significa que eu devo estar tecnicamente pior em todos eles. Não passou em branco, porém. A produção concluída do ano foi uma música, “Little Crystal“:

Pra completar a parte cultural, em termos de viagens o ano foi fantástico. Uruguai, Rússia, França, Suíça, Portugal. Praticamente terminei de “pintar” a Europa ocidental no mapa, salvo parte da Escandinávia e alguns micro-países.

O ano acadêmico foi ótimo, ótimo: paper publicado no SBLP, qualificação do doutorado, palestra no RIT em Moscou, Lua Workshop, e cadeiras de Prog II e Linguagens Formais na PUC. Algumas dessas coisas eram planejadas, outras foram oportunidades que superaram todas as expectativas.

Feliz ano novo!!!

🔗 O que é afinal a PEC 37?

Não preciso fazer introduções sobre tudo o que está acontecendo no país essa semana. Em meio às manifestações e protestos, o que eu estou mais gostando de ver é um clima de debate político, uma pausa na (e quem sabe o fim da?) apatia generalizada, e finalmente muita coisa está sendo falada, ouvida e pesquisada. Vários já falaram dos problemas das causas inócuas, excessivamente genéricas e que não levam a lugar nenhum (tipo “abaixo a corrupção!”, que é o mesmo que gritar “abaixo o crime!”). Algumas causas concretas, porém, estão sendo levantadas. Muita gente quer causas concretas, então quando uma aparece todo mundo está se agarrando nelas.

A que mais aparece ultimamente é o “não à PEC 37”. Mas o que é afinal a PEC 37?

tudo por um artigo
nesse livrinho

Se você clicou no link esperando que eu iria explicar, sinto muito decepcionar. Eu realmente não sei direito o que é PEC 37 e quais as suas implicações. Eu tentei entender o que é a PEC 37, li tudo o que chegou ao meu alcance a respeito nos últimos dias, e mesmo assim não consegui entender. Como não consegui entender, obviamente não tenho ainda opinião formada, se sou a favor ou contra.

Achei a dificuldade em conseguir entender isso, ao mesmo tempo que todo mundo está abraçando a causa rapidamente, alarmante.

Vou compartilhar com vocês aqui as informações que eu consegui coletar, pra pelo menos iniciar um debate e aí a gente tentar entender do que diabos se trata essa Proposta de Emenda Constitucional.

Em primeiro lugar, temos que riscar definições simplistas do tipo “é a PEC da Impunidade” ou “é a PEC da Legalidade“. Também não é “uma lei que impede de investigar políticos” ou qualquer definição de uma frase dessas.

Em segundo lugar, não podemos confundir duas coisas que estão circulando juntas: a PEC 37 e a PEC 33. A PEC 33 parece bem menos “controversa” por que é uma canalhice às claras: é só ver a definição dela no próprio documento oficial: Altera a quantidade mínima de votos de membros de tribunais para declaração de inconstitucionalidade de leis; condiciona o efeito vinculante de súmulas aprovadas pelo Supremo Tribunal Federal à aprovação pelo Poder Legislativo e submete ao Congresso Nacional a decisão sobre a inconstitucionalidade de Emendas à Constituição. Em suma, ela tira poder do STF e condiciona às suas decisões ao Legislativo: isso sim iria fazer os políticos se safarem do julgamento do STF! Não à PEC 33!

Agora, sobre a PEC 37… é bem mais complicado que isso. Até onde entendi, é uma grande briga entre o Ministério Público e as Polícias (Civil e Federal). Comecei também olhando o documento oficial: acrescenta o § 10 ao art. 144 da Constituição Federal para definir a competência para a investigação criminal pelas polícias federal e civis dos Estados e do Distrito Federal.

Aí já não dá pra tirar uma conclusão em uma frase. Mas atentem para o “definir”. A Constituição já define que o papel investigativo é da polícia, mas não define claramente que o MP não pode investigar.

(Antes disso, um parênteses: você sabe dizer o que é Ministério Público? Eu, pelo menos, não sabia dar uma definição clara. Lendo a descrição na Wikipedia que cita a constituição é super confuso (”é uma instituição permanente, essencial à função jurisdicional do Estado, incumbindo-lhe a defesa da ordem jurídica, do regime democrático e dos interesses sociais e individuais indisponíveis”… lindo, mas so what?), mas incrivelmente a Wikipedia em inglês é mais clara sobre isso: é o órgão brasileiro dos procuradores públicos independentes. “Procurador“, pelo menos, eu sei o que é: é o cara no julgamento que faz a acusação.)

O Ministério Público, atualmente, além de acusar, também conduz investigações em determinados casos, e existe um conflito sobre quem investiga o quê. Essa é a polêmica.

O lado do Ministério Público diz que faz um serviço relevante ao país e que se não for ela investigando vai ter impunidade, e que quanto mais gente investigando coisas no Brasil, melhor. Existe também o argumento de que há processos em andamento onde questiona-se a validade da investigação por ter sido feita pelo MP. Se a PEC 37 passar, essas investigações perderiam o valor e caras que já foram “quase pegos” poderiam se safar (até onde consegui entender não há valor retroativo, então quem já foi condenado não escapa). Outro argumento que é outros órgãos, como a Receita Federal, se aproveitam dessa “lacuna” da constituição e fazem investigações por conta própria sem passar pela polícia. Com a PEC 37 a lacuna é fechada e só as polícias podem investigar.

O lado da Polícia Federal diz que ela já investiga e que investigações importantes dela, como por exemplo a operação Satiagraha, acabam sendo travadas por outros órgãos. A PF diz também que ela está lá fazendo todo o trabalho de investigação criminal Brasil afora e que o MP só toma pra si as investigações que “dão mídia” e que o Poder Jurídico deveria trabalhar nas coisas que são a sua atribuição constitucional (e todos sabemos que o Jurídico está atolado de trabalho pra fazer) em vez de fazer o trabalho que é da polícia. O argumente é que situações onde um órgão faz o trabalho de outro desestabiliza o equilíbrio dos poderes (e é justamente porque a PEC 33 é ruim, por exemplo).

Até onde eu vejo, é uma guerra de poder e vaidades. Esse ano, no caso do Mensalão, o STF tem aparecido como os “salvadores da pátria” a ponto de ter gente querendo o ministro Joaquim Barbosa como presidente (wtf!?). Mas quem puxar um pouquinho da memória vai lembrar que há poucos anos atrás quem aparecia como “salvadores da pátria” era a PF, com suas Operações com Nomes Divertidos, que deram vários resultados interessantes (e também acabaram servindo de plataforma política pra uns e outros).

(Mais um parênteses: Eu pessoalmente, fico muito feliz de ver o STF e a PF fazendo trabalhos relevantes pro país, mas ao mesmo acho que eles não estão fazendo mais do que a sua incumbência e não são “salvadores da pátria”. Em tempos atuais, tem gente que fala do STF quase como se fosse o poder moderador da monarquia onde, em caso de qualquer dúvida, “manda pro Supremo decidir”.)

Em caso de situações polêmicas, é sempre muito tentador tentar descobrir quem é a favor, quem é contra, e com base nisso escolher um lado com base no quanto a gente confia num lado ou no outro. Tipo, “se os conservadores são todos a favor, então serei contra, ou vice-versa”. Por mais que esse atalho funcione muitas vezes, não é por aí — ter uma opinião sem pensar sobre ela não é ser mais politizado do que não ter opinião. É, sim, mais perigoso.

Pra esse caso da PEC 37, por exemplo, a divisão dos campos não parece ser nada clara. Tem gente grande dos dois lados contra e a favor e julgar na base do “quem é a favor e quem é contra” é difícil. Por exemplo, o Conselho Nacional de Justiça é contra, o Reinaldo Azevedo da Veja é contra (mas faz a mesma ressalva de que o “MP tenta agir como um Quarto Poder” que aqueles que são a favor fazem), um editorial do Estado de São Paulo é a favor, a OAB é a favor (e sugere alterações). É uma salada.

Ainda assim, tem coisas que me deixam de pé atrás. O Arnaldo Jabor, que era contra os protestos semana passada (”esses baderneiros não valem nem 20 centavos”) e que agora é a favor (”amigos, errei”) e publica uma frase como “amigos das redes sociais, lutem contra a PEC 37 ou nunca mais poderão conter a roubalheira”. O próprio Reinaldo Azevedo contradiz o Jabor: “há, evidentemente, um notável exagero nessa história de que, se aprovada, estará instaurada, no país, a impunidade como princípio. Não por isso. É falsa a ilação de que só o Ministério Público conduz investigações sérias e isentas.”

Todos queremos causas concretas. Mas antes de saber se sou a favor ou contra, quero entender a fundo essa questão pra não ter risco de ser massa de manobra de caras como o Jabor.

Toda informação é bem-vinda.

🔗 Comparando linguagens

Comparar linguagens de programação, seja discutindo na boa seus méritos e defeitos ou se digladiando em guerras santas do tipo “a ‘minha’ é melhor do que a ’sua’”, é um dos esportes preferidos da galera de informática em geral. Sendo pesquisador justamente da área de linguagens de programação, eu obviamente sou cheio de opiniões a respeito, mas eu evito entrar nos bate-bocas, que costumam ser sempre cansativos e repetitivos (ah, como eu mudei).

Esses dias, porém, li e ouvi alguns comentários que me deram vontade de dar um meta-pitaco no assunto. Dois alunos meus em sala de aula:

– Semestre passado o professor mandou fazer um trabalho de implementação, só que tinha que ser em Lisp.
– Lisp? O que é isso?
– Uma linguagem de programação lá, que o professor disse que era “melhor”.

Não sei se o tal professor disse isso, ou se foi a interpretação do aluno. Mas infelizmente comentários assim são muito comuns, ainda que não faça sentido considerar uma linguagem “melhor” em termos absolutos (melhor do que o que?) ou mesmo em termos relativos de forma não-qualificada. Por mais “tosca” que seja a linguagem X, quase sempre há algum aspecto em que dá pra fazer alguma qualificação do tipo “X é melhor que Y… no aspecto Z”, mesmo que Z seja algum aspecto menos técnico, como “é mais fácil de achar programadores pra contratar” — talvez no frigir dos ovos esse aspecto seja decisivo no negócio. Porém, dá pra argumentar também que nesse caso, não se está comparando as linguagens, mas sim o mercado de trabalho.

E é aí que eu quero chegar. O problema das discussões comparando linguagens é que em boa parte delas, não se está comparando as linguagens em si.

Comparar linguagens é, em primeiro lugar, comparar a especificação da linguagem. Sistema de tipos, estruturas de controle, sintaxe, semântica, biblioteca padrão, APIs para o mundo exterior. No nível mais fundamental, uma linguagem de programação é isso. Claro que isso não é a história completa, mas eu quero fazer um contraste do “resto todo” com a discussão sobre as “linguagens em si”.

Essa não é a história completa porque há muitos outros aspectos que acabam entrando em discussões sobre linguagens, de uma forma meio misturada. Pra citar alguns:

Desempenho - quando se fala de performance, não se está falando das linguagens, mas das suas implementações. Sem contar no “detalhe” de que algumas implementações são mais rápidas que outras em alguns aspectos e piores em outros. Nesse aspecto, o Benchmarks Game é particularmente incompleto porque eles arbitrariamente decidiram incluir só uma implementação de cada linguagem (quando ele ainda se chamava “Computer Language Shootout” tinha várias). Então, se alguém diz “PHP é mais rápido que Python”, está falando da implementação default, CPython? Ou da otimizada, PyPy? Tem uma boa diferença (e o Benchmarks Game usa a mais lenta). E PHP? A implementação original ou o HipHop, o tradutor pra C++ criado pelo Facebook? E estes não são os únicos.

E a linguagem em si? Ainda assim, em vários casos o design da linguagem em si afeta sim a performance que se consegue tirar das implementações: é um dos motivos pelo qual a implementação do tracing compiler de Lua (LuaJIT) tende a ser mais rápida do que a de JavaScript (V8) — a linguagem é menor e mais facilmente otimizável. Evidência disso é que a Mozilla definiu um subset de JS, asm.js, para ser uma implementação voltada a alto desempenho.

Ecossistema - linguagens não existem no limbo, então o suporte em volta é importante: bibliotecas, ferramentas de build, gerenciadores de pacotes, debuggers, IDEs (pra quem gosta), etc. Botei isso tudo sob o guarda-chuva de “ecossistema”, mas certamente esses itens são bem diferentes entre si e têm impactos diferentes (botei eles mais ou menos em ordem de importância pro meu gosto pessoal). Note que eu diferencio as bibliotecas padrão (que eu citei lá em cima na “linguagem em si”) das bibliotecas extras. Essas últimas são uma decisão de design do seu projeto; das primeiras não tem como fugir.

E a linguagem em si? Isso tudo é importante e afeta a produtividade de quem programa, claro. Mas, como no caso do desempenho, há uma diferença fundamental de discutir as linguagens em si: todas essas peças do ecossistema são trocáveis e a linguagem continua sendo a mesma. Você troca do Make pro CMake, mas C++ ainda é C++. Você troca de JQuery para Underscore, mas JavaScript ainda é JavaScript. Você pode optar por usar ou não RubyGems ou o LuaRocks. (E sim, acredite se quiser, há quem programa em Java sem IDE. ;) )

Killer applications - eu poderia botar isso junto com o ecossistema, mas achei que merecia um item próprio. De certa forma, a história das linguagens de programação e suas comunidades é a história das suas killer applications. Não tem como pensar em Ruby sem pensar em Rails, não há como falar de Lua sem citar o seu sucesso na indústria de jogos, de C e não falar de coisas baixo-nível tipo Unix, e assim por diante. E sim, muita gente vai escolher uma linguagem por causa de um framework específico, ou porque ela é “a linguagem que todo mundo usa pra fazer tal coisa”.

E a linguagem em si? Bom, muitas dessas killer applications das linguagens se derivam do design delas, afinal muitas linguagens foram criadas pra fazer alguma coisa específica: todo mundo fala maravilhas da linguagem R para estatística porque afinal, ela foi feita pra isso (e por consequência hoje tem milhares de bibliotecas prontas para estatística). Em outros casos, é quase uma casualidade: Python e Ruby são similares o suficiente para que o Rails pudesse ter sido criado em Python, e de fato hoje não faltam frameworks em outras linguagens que são de certa forma clones “de espírito” do Ruby on Rails.

“JavaScript” vs. “JavaScript: The Good Parts”: enough said.

Nesses casos, o que resta, além de diferenças menores de design dos frameworks (que, sendo, parte do ecossistema, sempre podem ser trocados), são as diferenças fundamentais das linguagens em si. E quão importantes essas diferenças são, já que a (bem) grosso modo dá pra implementar qualquer coisa em qualquer linguagem? São muito. Coisas como a sintaxe, sistemas de tipos, gerência de memória, são diretamente ligadas aos tipos de bugs que a gente tende a produzir quando programa. Você pode arranjar a melhor IDE, o melhor debugger, usar as melhores bibilotecas e frameworks, e ainda vai ser mordido vez que outra por regras de conversão de tipos bizarras. Como disse o Roberto esses dias, você pode ser a pessoa mais cuidadosa do mundo com todos os cantos escuros da linguagem e escolher um “subset seguro” pra trabalhar, mas quando você tiver que dar manutenção do código de outra pessoa (seja colega de trabalho ou código de alguma biblioteca), diga adeus ao “subset seguro”. O resto todo em volta tem jeito — troca-se a VM por uma mais rápida, troca-se a biblioteca por uma mais elegante — mas não há como fugir dos problemas da linguagem em si.

É por isso que PHP e JavaScript, mesmo com os melhores compiladores e as melhores bibliotecas do mundo, ainda vão ser linguagens “toscas”. Por outro lado, linguagens funcionais como Haskell (ou Lisp!), mesmo com toda a sua elegância conceitual, não são linguagens populares, em parte porque falta a elas toda a infraestrutura em volta pra serem uma opção pragmática. Felizmente, porém, o mundo não é feito só desses dois extremos. A gente tem que lembrar que a linguagem é o meio para um fim e que a linguagem que a gente programa não é o nosso time do coração no qual morreremos abraçados. Esses dias mesmo falei para um amigo que eu acho que ele não deve focar em se especializar pra ser um “programador Java” ou um “programador Python”, mas simplesmente um bom programador, e que essa polivalência acabaria rendendo mais em longo prazo. As lições mais importantes que a gente aprende nessa vida de programação se aplicam a todas as linguagens, e como nas linguagens naturais, quanto mais linguagens a gente aprende, mais fácil é aprender uma próxima. (Aliás, aprender uma nova linguagem é uma das melhores maneiras de se “reciclar” mentalmente.)

Moral da história: escolha a linguagem que resolve o seu problema, mas tendo a opção, escolha uma linguagem decente!

🔗 Mounting the SD card from your Android device on Linux over WiFi

Quick-and-dirty notes so I remember how to do it later. This is may all be mostly automatic in some distros (Ubuntu?) but here’s how to do it “by hand”. I may streamline the process myself for my machine in the future, but this is a minimal process that works.

My setup:

  • Samsung Galaxy S3 SGH-T999, not rooted
  • my own hacked up version of GoboLinux, so this should work on any distro

The steps:

  1. Install Droid NAS on your phone. Their description say it “most probably […] won’t work” on Linux, but it is based on Bonjour (aka mDNS protocol) and SMB, and there are Linux clients for that.
  2. Create a directory for your local mount point (mine is /Mount/Phone) and then mount it like this:

    mount -t cifs -o port=7777 //192.168.0.106/"SD Card" /Mount/Phone

    (You can find your phone’s IP with avahi-browse -altr, if avahi-daemon is running).

TODO: convince mount.cifs to use a logical name instead of IP there. Might need to use avahi and nss-dns for that; by the way, if you get an error such as “Connection “:1.10” is not allowed to own the service “org.freedesktop.Avahi” due to security policies in the configuration file” when using avahi-daemon, follow the instructions found here).


Follow

🐘 MastodonRSS (English), RSS (português), RSS (todos / all)


Last 10 entries


Search


Admin