← Pol Milian

Notes on software

Things I’m learning, small discoveries, and occasional longer articles.

Follow via RSS ↗

Iterator vs IntoIterator & cfg

Today I split my time between the iterators video and my CLI project.

I also refreshed the difference between Iterator and IntoIterator.

In yesterday’s journal I got a bit into the Iterator trait. Well, IntoIterator is a trait that implies that something can be converted into an Iterator.

For example, Vec<T> itself is not an iterator. But since it implements IntoIterator, it can be converted into an Iterator.

let v = vec![1, 2, 3];

let iter = v.into_iter();

assert_eq!(Some(1), iter.next());
assert_eq!(Some(2), iter.next());
assert_eq!(Some(3), iter.next());
assert_eq!(None, iter.next());

In the video, there’s also an interesting comparison between different kinds of loops:

fn main() {
  let vs = vec![1, 2, 3];

  for v in vs {
    // consumes vs, owned v
  }
  for v in vs.iter() {
    // borrows vs, & to v 
  }
  for v in &vs {
    // equivalent to vs.iter()
  }
}

Luckily, the compiler will help us to choose the correct one, but it is fundamental to know our fundamentals :)

Cfg

Today I also learned about cfg: https://doc.rust-lang.org/rust-by-example/attribute/cfg.html

This came by from working on my CLI project. I know from experience that it’s the best way to learn.

This CLI project I’m doing is a Pomodoro timer. I want to play a notification sound, so I’m using rodio.

There was a useful log message that appeared constantly. Checking the docs, there is a way to eliminate it. And I thought: how can I have it on my development but not in the released version?

And there was the answer: the cfg attribute and macro. With cfg, you can conditionally run code and booleans depending on many factors: https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute

I ended up doing:

sink_handle.log_on_drop(cfg!(debug_assertions));

Where cfg! is a macro that returns a boolean, and debug_assertions will differentiate between development and production: https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions

Starting "Rust for Rustaceans"

Recently, with all the AI psychosis, I realized that I miss programming. I miss learning hard things, figuring out the solution, structuring code.

A few years ago I got into Rust and wrote a couple of short, easy programs. My favorite part is how I could leverage WebAssembly to write ultra-perfomant web apps.

In one of my previous roles, they were enforcing AI aggresively, without any reasoning or criteria: unlimited Claude Code tokens, AI-generated Jira tickets, no human code reviews. It was kind of a mess, but understandable when code quality really does not matter.

These days, I got some more free time so I decided to resume my Rust journey.

Today I started reading Rust for Rustaceans, the Jon Gjenset book. I’m a big fan of Jon’s streams. I remember watching them in the past and not understanding shit, hoping that through pure osmosis, some knowledge seeped into me.

In the past I also gave a fair shot into reading his book, but it was too advanced for me. So I did it the right way: The Rust Book, rustlings, wrote some small CLI programs on my own, a WebAssembly program… This gave me a better overview.

Finally I can say that today I made it through the first chapter without issues. I still feel it’s kind of advanced, but in a good way. I love to understand what I do, how it works underneath. I’m a firm believer in craft and care, and code quality.

This first chapter focuses on different types of memory: stack, heap, static. It also presents the borrow checker & ownership. I would say this is the number one concept that you need to succeed in Rust programming. Understanding this also helped me a ton in my JavaScript programming. Reasoning about what I’m doing exactly and if I’m copying/referencing. Rust programming feels more real compared to JavaScript, and it’s one of the aspects I enjoy more.

By reasoning about what we are doing with memory & variables we can produce a better, more optimized program. And this is just high-level, just the beginning.

 

Primitive vs reference values in JS

In this post, we will take a look at a super common interview question: primitive vs reference values in JavaScript.

What is a primitive value?

In JS, there are 6 primitive values: number, string, boolean, undefined, null and symbol.

You can think of them as the base, hence the name primitive. These values are not objects and they don’t have methods.

What is a reference value?

The short answer is: anything that is not a primitive value is a reference value. They are typeof "object". We are talking about objects, arrays, functions, etc.

Key differences

The key difference is how these values behave under the hood. Specifically, how they store their values in memory.

The primitive values would have the value in memory, while the reference values would have a reference to that location in memory (the memory address), and not the value itself.

For example:

let name = 'Jesus';
let nickName = name;

name = 'Juan';

console.log(name); // 'Juan'
console.log(nickName); // 'Jesus'

We are only using primitive values here, so everything makes sense. Right?

Now, let’s take a look at a reference values example:

let jose = {
	type: 'Person',
	name: 'Jose'
};

let juan = jose;

juan.name = 'Juan';

console.log(jose.name); // 'Juan'
console.log(juan.name); // 'Juan'

See? In here, the juan variable is referencing the same spot in memory as the jose variable. That is why when we change the name property in one of them, we will be changing it in both.

This behavior also explains why if we compare two seemingly equal reference values, the result will be false. For example:

const fruit = {
	color: 'Yellow',
	name: 'Banana'
};

const snack = {
	color: 'Yellow',
	name: 'Banana'
};

fruit === snack; // false

So primitive types are compared by their value, while reference types are compared by their reference.

Lastly, remember that primitive values are immutable. So when you change a primitive value, what you are doing is replacing the in-memory value. You are not modifying it like you can do with reference values.