Michael Chaney Profile picture
Oct 23 1 tweets 3 min read Read on X
@joeldrapper mentioned hash rocket syntax yesterday, and the fact that it's not some deprecated part of Ruby. It's still the standard way to create a hash with strings as keys. Which, by the way, is probably what you want.

@rails makes heavy use of ActiveSupport::HashWithIndifferentAccess, which acts exactly like a hash except symbols and strings are interchangeable as keys. In other words:

> h = { a: 5 }
> h["a"]
5
> h[:a]
5

This is not the natural order of the universe, and honestly, if you're using hwia yourself it's a code smell.

I just ran into this yesterday, which is why it was fresh in my mind. I mindlessly created a hash to hold some info about various LLM providers and models:

providers = {
openai: { (some openai stuff)
},
grok: { (some grok stuff)
}
}

This is perfectly fine if you're going to just reference this hash later on in code:

> providers[:openai][:default_llm_model]
gpt-4o

The issue is that I'm storing the provider and llm_model (note: naming "llm_model" to differentiate from "model" in the rails sense) in a table. So these are coming in from a form where someone chose them from a dropdown. It's internal so I don't care to make the form fancy, but I do want to have a validation to make sure that the llm_model chosen is associated with the given provider.

validate :llm_model_associated_with_provider

def llm_model_associated_with_provider
# Next line fails because the keys are symbols
provider_info = providers[self.provider]
unless self.llm_model.in?(provider_info[:llm_models])
errors.add(:llm_model, "isn't associated with the chosen provider")
end
end

Using symbols for keys is fine in many instances, usually for settings and such where you're not going to write code that dynamically digs around in the hash. The above is fine as long as my code explicitly references information for providers[:openai] and such.

But it falls apart when I need to dynamically reference something because my key will naturally be a string if it's coming from a database, a file, or a set of params/attributes. In other words, just about anywhere I would get data from.

I could "fix" it, of course, by:
provider_info = providers[self.provider.to_sym]

That's more code smell.

I could also convert my hash to be a HashWithIndifferentAccess. That's a code smell.

The proper way to handle it is to simply use hash rocket syntax so that the keys are strings. Problem solved.

providers = {
"openai" => { (some openai stuff)
},
"grok" => { (some grok stuff)
}
}

It's so easy to write "openai:" - it's four fewer characters, ":" is home row/home position and it's the only shifted character. The hash rocket way is mentally and physically more work as it involves three shifts and a character on the top row followed by a character on the lower row. Look, I get that this isn't the same as busting rocks with a sledgehammer in the quarry, but we subconsciously make those determinations.

As Joel said, this isn't a deprecated syntax. It's really the default and normal syntax. Using symbols as we do is the abnormal way of handling it, but rails made that common.

This caused issues in early rails/ruby, by the way, as symbols weren't GC'd back in the old days. It was Ruby 2.2 that changed that.

Anyway, I do offer a service associated with this. For the price of a plane ticket and a meal, I can help. If you're tempted to use either HashWithIndifferentAccess or ".to_sym" in a case like this, I can fly to wherever you are, smack your knuckles with a wooden ruler a few times, eat somewhere, and then fly home. Let me know if you need my help.

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Michael Chaney

Michael Chaney Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(