Live data from Hacker News

Ruby's hash is a Swiss-army knife

akshaykhot.com

71–80 of 81 posts

Re: Ruby's hash is a Swiss-army knife

#72
post #22

Since Ruby 3, the automatic coercion of keywords to a hash—the second example underneath "Passing Hash to Functions" in this post—is considered a legacy style and is generally frowned upon in new code. That is to say, code like the second call to `foo` here: def foo(kwargs = {}) kwargs end foo({k: 1}) # ok: passing hash argument foo(k: 1) # ok: keywords coerced to hash One of the strongest arguments for avoiding this…

This might be me having huffed too many types lately, but I feel like I would want that to break .

Adding a parameter that has a sensible default value? I don't think I'd want that to break anything.

Re: Ruby's hash is a Swiss-army knife

#73
> as a programmer building run-of-the-mill CRUD web applications, having so many choices can be really daunting and confusing. When do you choose which type?

I feel similarly after getting back into Java after years of Javascript. Java has a ridiculous number of arrays and lists: Object[], List, Iterator, Iterable, Stream, and I think I'm forgetting a few. Some functions want or return one, some want or return another. I'm constantly convertings these from one to the other, and it's never pretty. (What the hell is a Spliterator?!)

Meanwhile, in Javascript, there's just the Array. (It's not even really an array, but a hashmap that only takes integers as index, but nobody cares; it works.)

And, like Ruby, Javascript also has easy object literals that is basically the exact same as the hash in Ruby. If there are any meaningful differences, I'd love for someone to enlighten me. The only difference I'm aware of, is that the preferred type for keys in Ruby is the Symbol, which is a very lightweight string, whereas in JS it's just a regular string.

But, like the author, I strongly prefer to work in a language that just has a couple of sensible data types instead of making me choose from thousands that have no meaningful differences beyond their incompatibility.

Re: Ruby's hash is a Swiss-army knife

#74
post #63

Hash is so powerful in Ruby that people often overuse them. One of the most common issues I found on Ruby code-bases is to not create classes to represent their domain and simply use hashes everywhere. The downside is that a hash has no shape. It can (and will) be anything you want it to be, often causing havoc once the system grows. Checks for keys everywhere. Almost all statements use the safe navigation because yo…

This is perhaps the biggest killer feature of typescript: that your object literals (which are basically hashes) can have types. Or possibly interfaces.

Re: Ruby's hash is a Swiss-army knife

#75
post #72
post #22

Earlier quoted context omitted.

This might be me having huffed too many types lately, but I feel like I would want that to break .

Adding a parameter that has a sensible default value? I don't think I'd want that to break anything.

The inverse here - specifying {} directly - does not at a glance imply a default value is being constructed.

(Or perhaps it does and this is just some Ruby-ism I'm not exposed to)

Re: Ruby's hash is a Swiss-army knife

#76

Earlier quoted context omitted.

Selling it as associative array is nice. (And I know the docs do that, too) It's a doubly linked list, array, hashmap all in one, with some weird magic when handling numeric indices. There's often the time when using another language that I made a bad choice by picking either an array or hash or list while later I need one of the other properties PHP would give me by default. The extra cost for most uses is neglectib…

> It's a doubly linked list, array, hashmap all in one, with some weird magic when handling numeric indices. In what way, exactly, is PHP's associative array (a hash table of course, like all these things) a doubly linked list ? Sure, in a language which isn't very fast anyway, I can believe it's reasonable to use your hashtable as an array, O(1)~ or O(1)* [Expected or Amortized constant time] probably feels enough l…

Seems to have changed in the implementation indeed and I now didn't spend much time thinking through the current implementation.

But the old implementation had pointers to next and last (previous) element in the list: https://github.com/php/php-src/blob/PHP-5.3/Zend/zend_hash.h...

Re: Ruby's hash is a Swiss-army knife

#77
post #75
post #72

Earlier quoted context omitted.

Adding a parameter that has a sensible default value? I don't think I'd want that to break anything.

The inverse here - specifying {} directly - does not at a glance imply a default value is being constructed. (Or perhaps it does and this is just some Ruby-ism I'm not exposed to)

That's kind of the point of default values, though. If you wanted to make a change to the method and you want it to break to alert you to all the calls, then you can add a keyword without adding a default value for it.

    def foo(kwargs = {}, frob:)
      kwargs
    end

Re: Ruby's hash is a Swiss-army knife

#78

Earlier quoted context omitted.

> It's a doubly linked list, array, hashmap all in one, with some weird magic when handling numeric indices. In what way, exactly, is PHP's associative array (a hash table of course, like all these things) a doubly linked list ? Sure, in a language which isn't very fast anyway, I can believe it's reasonable to use your hashtable as an array, O(1)~ or O(1)* [Expected or Amortized constant time] probably feels enough l…

Seems to have changed in the implementation indeed and I now didn't spend much time thinking through the current implementation. But the old implementation had pointers to next and last (previous) element in the list: https://github.com/php/php-src/blob/PHP-5.3/Zend/zend_hash.h...

Oh I see. Yes, this is a very common way for C programmers - in particular - to make a hash table, it's the design that C++ enshrines as std::unordered_map and it's the data structure you'd have been taught in a University data structures course in the 1980s, and maybe even the 1990s [depending on who is teaching and where]

While internally this is indeed using linked lists, I don't think you can make use of that from PHP which is what I'd imagined was meant. Suppose I had a million integers that I found somewhere, and then I want to splice in a different million integers I have, so that in total there are two million integers. With linked lists that's very cheap, basically instant, but with most data structure, including a hash table, not so much.

Linked Lists are very rarely what you needed, even though when they are what you needed they're invaluable. They are really easy to implement in C, so it's sort of a "I've got a hammer, now all I see are nails" situation in C.

Re: Ruby's hash is a Swiss-army knife

#79

Earlier quoted context omitted.

Seems to have changed in the implementation indeed and I now didn't spend much time thinking through the current implementation. But the old implementation had pointers to next and last (previous) element in the list: https://github.com/php/php-src/blob/PHP-5.3/Zend/zend_hash.h...

Oh I see. Yes, this is a very common way for C programmers - in particular - to make a hash table, it's the design that C++ enshrines as std::unordered_map and it's the data structure you'd have been taught in a University data structures course in the 1980s, and maybe even the 1990s [depending on who is teaching and where] While internally this is indeed using linked lists, I don't think you can make use of that fro…

Well, the hash table also uses list for handling collisions, but also using it to doubly link all elements.

And it's true, on modern hardware linked list are often bad due to data locality making iteration bad ... but that data structure was designed before (while, as said, revamped meanwhile ...)

But it's quite fancy. If you deal with it with "proper" indexed keys data will be packed in an array (or vector, ifyou prefer C++ terms; while most data stored in there is just pointers taking away some benefit of the packing...) while also keeping the doubly-linked-list pointers and once you have holes in it or string keys or something it plays hash and gives away some of the ordered storage ...

In the end that extra bookkeeping everywhere makes it slow and bloated for everything, but from a usage perspective it's quite nice.

Re: Ruby's hash is a Swiss-army knife

#80
post #64
post #63

Hash is so powerful in Ruby that people often overuse them. One of the most common issues I found on Ruby code-bases is to not create classes to represent their domain and simply use hashes everywhere. The downside is that a hash has no shape. It can (and will) be anything you want it to be, often causing havoc once the system grows. Checks for keys everywhere. Almost all statements use the safe navigation because yo…

Ruby newly added type system can also help here. For starters, it'd be nice to know what type(s) the keys and values can be.

That's what POROs are there for. I truly don't want a faux type system only to then keep using hashes for everything...
Post reply on HN