Sign in

Felipe O. Carvalho

@felipe.rs
1.5K followers 503 following 1.1K posts

SWE @ dbt Labs. Past: SDF, VoDa, Spotify. Apache Arrow/Databases/Compilers/DistSys. Rust/C++/OCaml/TLA+. 🇧🇷 → 🇸🇪 → 🌎 bento.me/felipe / felipe.rs

PostsRepliesMedia
Felipe O. Carvalho @felipe.rs · 06/09/2026
💯 Reminds me of the Zig debate in July.
Only if you have full project control and free time, you can use such a language. The privileged position that is also required to forbid agentic programming altogether.
020
Felipe O. Carvalho @felipe.rs · 18/02/2026
In Arrow C++, we have “length” of arrays for the “count” and buffers have “size” in bytes. But things get confusing when STL code is mixed because vector::size() is the length/count and not the “size” in bytes. t.co/ZGkA8xvy8R
010
Felipe O. Carvalho @felipe.rs · 13/02/2026
Good time to be CLI maxxing: - @neovim.io - tmux - smug (to start tmux sessions from YAML files) - git worktrees (multiple repo checkouts for parallel agents) - dotfiles in a git repo synced across macOS and Linux machines
040
Felipe O. Carvalho @felipe.rs · 16/01/2026
vibe coded unit tests
0101
Felipe O. Carvalho @felipe.rs · 05/01/2026
Wrote a small bitset class for it. No allocation before more than 64 booleans (i.e. struct fields).
000
Felipe O. Carvalho @felipe.rs · 05/01/2026
Serialization of @CapnProto messages to JSON using runtime reflection [1], serde_json [2], and base64 [3]. gist.github.com/felipecrv/16...
150
Felipe O. Carvalho @felipe.rs · 30/12/2025
É a Spotifização do design.
100
Felipe O. Carvalho @felipe.rs · 20/11/2025
Gold
DDR5
011
Felipe O. Carvalho @felipe.rs · 13/11/2025
You can post about semaphores, atomics, and syscalls on LinkedIn if you want.
Weekend Rust excursion: implementing a semaphore that is as clean as the C++20 implementation.

You can implement a semaphore using a Mutex and a Condvar, but these are heavy-weight constructs. A semaphore is a very simple primitive and doesn't need all the functionality provided by these. All we need is the equivalent of std::atomic<uint32_t>::wait() and std::atomic<uint32_t>::notify_all() available in C++20. The equivalent doesn't exist in stable Rust yet.

atomic-wait is a very minimal crate that provides a portable façade to the futex() syscall (Linux), WaitOnAddress/WakeByAddressAll (Windows), and __libcpp_atomic_wait/__cxx_atomic_notify_all (for other platforms).

Just include that crate, and then you can implement a very clean semaphore by combining atomic_wait::wait()/wake_all() with the standard Rust Atomic32.
030
Felipe O. Carvalho @felipe.rs · 08/11/2025
If we forbid the inlining, the caller is forced to put i on the stack str r0, [sp, #4] to pass the ptr to add10 add r0, sp, #4 // put the ptr relative to the stack ptr on r0 before call then the value is loaded from the stack into r1 before the printf call ldr r1, [sp, #4]
__attribute__((noinline))
int add10(int *num) {
    return *num += 10;
}
030
Felipe O. Carvalho @felipe.rs · 08/11/2025
add10(int *) versus add10 inlined. When you take a "pointer" from a local variable and "pass" it to a function, but the compiler knows the pointer is not a pointer but the register that contains the local variable.
#include <cstdio>

int add10(int *num) {
    return *num += 10;
}

int external_int();

int main(int argc, char *argv[]) {
    int i = external_int();

    add10(&i);

    printf("%d", i);
    return 0;
}
240
Felipe O. Carvalho @felipe.rs · 08/11/2025
It’s only a 20-ish% increase from June in Brazil, so I’m securing mine before they have to renew their inventory and increase it even more.
380 BRL for Kingston Furybeast 16GB in June (~70 USD)
010
Felipe O. Carvalho @felipe.rs · 26/10/2025
“wE lAunChed our SaaS a mONth ago and alReady mADE it to 1M ARR”
Friendly reminder that multiplying revenue by 12 is not ARR
120
Felipe O. Carvalho @felipe.rs · 16/09/2025
To be fixed in C++ 2026.
130
Felipe O. Carvalho @felipe.rs · 16/09/2025
I installed Termios on my iPhone and I can SSH to my MacBook (Tailscale FTW), run tmux, Neovim and Amp (AI coding agent CLI) from anywhere. 😌
010
Felipe O. Carvalho @felipe.rs · 08/09/2025
Very observant of Sam to notice the consequences of AI on the internet.
Sam Altman: i never took the dead internet theory that seriously but it seems like there are really a lot of LLM-run twitter accounts now
140
Felipe O. Carvalho @felipe.rs · 19/06/2025
Puns in Gothenburg 🇸🇪
020
Felipe O. Carvalho @felipe.rs · 06/02/2025
New book ✨
Practical Foundations for Programming Languages 2nd edition.
Robert Harper
1200
Felipe O. Carvalho @felipe.rs · 27/01/2025
They removed optionals when transitioning to proto2 to proto3 and then people demanded their optionals back. Optionals came back, but implement in a much worse manner. Putting it under an experimental flag didn't deter people from using it elsewhere though.
This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set.\n" }
120
Felipe O. Carvalho @felipe.rs · 23/12/2024
I think I’ve achieved the right level of @fly.io networking understanding.
130
Felipe O. Carvalho @felipe.rs · 23/12/2024
I remember when it was nVIDIA and not Nvidia or NVIDIA.
2172
Felipe O. Carvalho @felipe.rs · 18/12/2024
I'm parsing JSON that contains numbers with two decimal places and I want to store them as Decimals on the database. Python offers a way to avoid the limitations of the floating point representation of the number strings that appear in the JSON text! This will work even when numbers are not in "".
parse_float is an optional function that will be called with the string of every JSON float to be decoded. By default, this is equivalent to float(num_str). This can be used to use another datatype or parser for JSON floats (e.g. decimal.Decimal).
050
Felipe O. Carvalho @felipe.rs · 14/12/2024
Needy Duolingo owl asking me to extend my daily streak.
010
Felipe O. Carvalho @felipe.rs · 09/12/2024
I guess that kinda makes protobuf unsuitable for the representation of ASTs.
[DISCUSS] Workaround Protobuf deserialization depth limit in Substrait

We have accidentally encountered a deserialization limit of official protobuf library with a deep nesting. The limit is 100 (https://protobuf.dev/programming-guides/proto-limits/#depth), that is, the library will fail to parse a message if it contains more than 100 nestings. So I would like to discuss extending Substrait to reference fragment of scalar expression as it already does for the RelOp tree.
050
Felipe O. Carvalho @felipe.rs · 07/12/2024
🤿|🤿🤿🤿+ Made it more interesting ;)
000
Felipe O. Carvalho @felipe.rs · 07/12/2024
httpcats.com/500.jpg
110
Felipe O. Carvalho @felipe.rs · 07/12/2024
I wrote a SQL query. #sql #datascience #bolhadev
WITH time_series AS (
  SELECT
    "returns".date,
    rf.rate rf_rate,
    rf.log1p rf_log1p,
    "returns".log_return,
  FROM "returns"
  ASOF JOIN rolling_rf_rate rf ON "returns".date >= rf.date
  ORDER BY "returns".date
),
rolling AS (
  SELECT
    date,
    -- annualized risk-free rate
    rf_rate,
    rf_log1p,

    -- daily returns and excess returns
    log_return,
    log_return - (rf_log1p / $trading_days_per_year) AS excess_log_return,
    EXP(log_return) - 1                              AS simple_return,
    EXP(excess_log_return) - 1                       AS excess_simple_return,

    -- window offset and dimension
    first_value(date) OVER rolling_window AS window_start_date,
    COUNT(*)          OVER rolling_window AS window_trading_days,

    -- annualized values based on log returns
    (SUM(log_return) OVER rolling_window * $trading_days_per_year) /
         window_trading_days              AS rolling_annual_log_return,
    rolling_annual_log_return - rf_log1p  AS rolling_annual_excess_log_return,
    (STDDEV_POP(excess_log_return) OVER rolling_window) *
        SQRT($trading_days_per_year)      AS rolling_annual_log_stddev,

    -- rolling volatility as a simple ratio
    EXP(rolling_annual_log_stddev) - 1    AS rolling_annual_volatility,

    -- sharpe ratio
    rolling_annual_excess_log_return / rolling_annual_log_stddev AS rolling_sharpe_ratio,

  FROM time_series
  WINDOW rolling_window AS (
    ORDER BY date RANGE BETWEEN $window_m1 PRECEDING AND CURRENT ROW
  )
)
SELECT * FROM rolling
WHERE
  -- exclude the first window that may not have enough data
  date >= (SELECT MIN(date) FROM rolling) + $window_m1
1103
Felipe O. Carvalho @felipe.rs · 06/12/2024
Yet another case of “hardware companies should be creating compilers and new programming models instead of just hardware.” NVIDIA is a hardware and compiler company.
Lisa Su (AMD): I think our strategy is that we have to increase performance continually. For gaming in particular, the gaming software developers have not necessarily used all the cores from time to time. There is no physical reason we couldn't go past 16 cores. The key is that we're going at a pace that the software guys can and do utilise it.
082
Felipe O. Carvalho @felipe.rs · 03/12/2024
Updated version with zip().
    if len(dates) == 0:
        yield (start_date, end_date)
        return
    if start_date < dates[0]:
        yield (start_date, dates[0] - timedelta(days=1))
    for d0, d1 in zip(dates[:-1], dates[1:]):
        d0p1 = d0 + timedelta(days=1)
        if d0p1 < d1:
            yield (d0p1, d1 - timedelta(days=1))
    if end_date > dates[-1]:
        yield (dates[-1] + timedelta(days=1), end_date)
010
Felipe O. Carvalho @felipe.rs · 03/12/2024
Just implemented this function. A nightmare of off-by-one errors. Do you have a more elegant way of implementing it?
def generate_holes(dates: list, start_date: datetime.date, end_date: datetime.date):
    """
    Generate holes in a sorted list of dates.

    Parameters
    ----------
    dates : list
        Sorted list of dates.

    start_date : datetime.date
        Start date (inclusive).

    end_date : datetime.date
        End date (inclusive).

    Yields
    ------
    tuple
        A tuple with the start and end dates of a hole.
    """
    if len(dates) == 0:
        yield (start_date, end_date)
        return
    expected = start_date
    i = 0
    while True:
        while expected == dates[i]:
            expected += timedelta(days=1)
            i += 1
            if i >= len(dates):
                break
        if i >= len(dates):
            break
        hole_last = dates[i] - timedelta(days=1)
        yield (expected, hole_last)
        i += 1
        if i >= len(dates):
            break
        expected = dates[i]
    if dates[-1] < end_date:
        yield (dates[-1] + timedelta(days=1), end_date)
120
Felipe O. Carvalho @felipe.rs · 01/12/2024
Built-in iOS Calculator app is finally decent!
010
Felipe O. Carvalho @felipe.rs · 22/11/2024
“creators” losing engagement after the changes made to Threads’ algorithm
Post that triggers lots of replies being replicated by multiple users farming for engagement:

“Quero saber quem foi o cabeçudo que me inventou um caderno de 96 folhas, 96? Pq 96 e não 100?”

Translation: “I want to know who was the big head who invented a 96-page notebook, 96? Why 96 and not 100?”
000
Felipe O. Carvalho @felipe.rs · 22/11/2024
Arrow 18 (released by the end of October) is the last release to have so many commits (1 commit = 1 PR) from me. arrow.apache.org/blog/2024/10...
    65	Sutou Kouhei
    41	Raúl Cumplido
    35	Antoine Pitrou
    21	Vibhatha Lakmal Abeykoon
    19	Dane Pitkin
    16	Felipe Oliveira Carvalho
    16	Jonathan Keane
    16	Joris Van den Bossche
    16	Rossi Sun
    16	mwish
    13	Joel Lubinitsky
     9	Laurent Goujon
     7	Lysandros Nikolaou
     7	Neal Richardson
     6	Bryce Mecum
     6	David Li
     5	Matt Topol
030
Felipe O. Carvalho @felipe.rs · 18/11/2024
Thinking in terms of array operations which means memory access operations are sequential/predictable. The jax.numpy API is inspired by numpy, but some things are very different.
https://jax.readthedocs.io/en/latest/_autosummary/jax.Array.at.html
010
Felipe O. Carvalho @felipe.rs · 17/11/2024
000
Felipe O. Carvalho @felipe.rs · 17/11/2024
Just watched “Ainda Estou Aqui” (#iamstillhere) ⭐️⭐️⭐️⭐️⭐️ A movie hits you like a rock. #aindaestouaqui
Movie cover of “Ainda estou aqui” showing Selton Mello and Fernanda Torres
130
Felipe O. Carvalho @felipe.rs · 16/11/2024
CQRS não é uma "boa prática". É um tipo de otimização em sistemas distribuídos que é muito pouco resistente a bugs em máquinas de estado se comunicando via passagem de mensagens incrementais. A primeira resposta para alguém pensando em implementar CQRS é "NÃO".
121
Felipe O. Carvalho @felipe.rs · 16/11/2024
A cada 6 horas eu ganho 30 seguidores nos últimos dias. Sim, o Bluesky está ganhando tração fora do Brasil. No horário mais calmo, os servidores estão recebendo a mesma carga que recebiam no pico da invasão brasileira.
110
Felipe O. Carvalho @felipe.rs · 16/11/2024
Leia código de verdade em vez de código de vendedor de livro/curso que diz que funções tem que ter apenas 5 linhas e que você não deve usar else. cpython/Lib/threading.py tem 1599 linhas, 11 classes, várias funções. Leia a implementação das funções que você usa.
2130
Felipe O. Carvalho @felipe.rs · 16/11/2024
Quer parar de codar fofo? Esqueça o Clean Code e comece a se sentir confortável em escrever mais de 1000 linhas de código em um único arquivo e modularizar DEPOIS. Escrever funções longas (100+ linhas) e extrair funções DEPOIS se elas forem chamadas mais de uma vez ou forem funções puras. #bolhadev
> wc -1 bin/tower.py
1074 bin/tower.py
4338
Felipe O. Carvalho @felipe.rs · 15/11/2024
I saw capybaras irl this week
220
Felipe O. Carvalho @felipe.rs · 11/11/2024
Here is a taste of what it looks like. This is the configuration for a script I'm writing for managing a small data ingestion pipeline.
repository {
  namespace "b3" {
      path "archive/b3"

      table "negociosavista" {
          glob_pattern "*/*/*/*.parquet"
          ingestion {
              incremental append_only=true
              source "b3_raw.negociosavista"
              partition_by "year" "month" "day"
          }
      }

      table "instruments" {
          glob_pattern "*/*/*.parquet"
      }
  }
010
Felipe O. Carvalho @felipe.rs · 11/11/2024
Tem gente reclamando dessa questão do ENEM. Questão bem elaborada. Cenário plausível. Dá pra resolver por tentativa e erro. Aí vem o candidato e chuta 21.
Ao calcular a média de suas notas em 4 provas, um estudante dividiu, por engano, a soma das notas por 5. Com isso, a média obtida foi 1 unidade menor do que deveria ser, caso fosse calculada corretamente.

O valor correto da média das notas desse estudante é
A. 4.
B. 5.
С. 6.
D. 19.
040
Felipe O. Carvalho @felipe.rs · 08/11/2024
Programming in JAX feels like doing C++ template meta-programming without all the verbosity and hacks based on template specialization quirks.
Computing the Augment Dickey-Fuller statistic to check if a time series is stationary or not.
020
Felipe O. Carvalho @felipe.rs · 07/11/2024
Like... I still haven't found a way to elegantly ensure my code runs with these parameter pre-conditions being checked. At least in unit tests. During development, I comment out the jax.jit transformation to catch errors, but a jax.jit() somewhere might "remove it".
000
Felipe O. Carvalho @felipe.rs · 01/11/2024
Studying time series analysis and using JAX to implement the algorithms. #jax #machinelearning #optimization #statistics
Linear regression model based on TimeSeries as input.

The simplest model with a weight and bias parameter. Very useful for understanding the basics of training models.
The AR(p) model. A very simple auto-regressive model.AR(2) applied to a linear series that alternates with some noise. It uses the last two measurements to predict the next.
170
Felipe O. Carvalho @felipe.rs · 31/10/2024
This is over 127.0.0.1 so it's measuring the CPU overhead and not benefiting from transferring less data due to good compression ratios. [zstd] is HTTP compression. [identity+<CODEC>] is IPC compression.
110
Felipe O. Carvalho @felipe.rs · 27/10/2024
Pen sketch on tiny notebook
180
Felipe O. Carvalho @felipe.rs · 27/10/2024
Caetano Veloso and Maria Bethânia in concert. Recife, PE, Brazil.
020
Felipe O. Carvalho @felipe.rs · 24/10/2024
I had to tweak the size of the butterfly to make it look good as an icon.
010