Rules for combining pipe and parentheses in Ruby - ruby

In ruby you can do things like:
[[:a, [:z, 1]]].map{|one, (two, three)| three}
=> 1
What are limits and general rules in combining pipe sections with parentheses?

As others mentioned, this is called "array destructuring" or array decomposition. See: https://ruby-doc.org/core-3.1.2/doc/syntax/assignment_rdoc.html#label-Array+Decomposition .

Related

Ruby symbol syntax with strings ex "a-b": "d"

Starting in ruby 1.9 you could use the new syntax for symbols inside of hashes
Before 1.9
{:a => 'b'}
1.9 and later
{a:'b'}
But why isn't there a similar thing for symbols that contain strings that cannot be easily converted {:"a-b" => 'c'} like
{"a-b": 'c'}
Is there something in the Ruby lexical parser that would prevent this from happening? or fundamental reason why this was not also implemented?
Because Matz decided against it:
Iff {'key': 'value'} means {:key => 'value'} I have no objection.
[but later on...]
The discussion has gone away in the wind without making any consensus.
So I marked this 'rejected'. My point is clearly stated in the first comment.
Cited from https://bugs.ruby-lang.org/issues/4801

Use case for using array as ruby hash key

Ruby allows using an array as a hash key as shown below:
hash1 = {1 => "one", [2] => 'two', [3,4] => ['three', 'four']}
I am not clear on what common use case for this would be. If people can share some real-world scenarios where this is useful, I would appreciate it.
A great example why you'd want to store arrays as hash keys is for memoizing.
This is an example of how an array as a hash key is useful:
def initialize(*args)
#memoizer ||= {}
return #memoizer[args] if #memoizer[args]
# do what you will with the args in this initializer,
# then create a new instance for the future.
#memoizer[args] = some_calculation(args)
end
I think you're overcomplicating things here. It isn't that Arrays are allowed as keys, it is that almost any object can be a key. From the fine manual:
A Hash is a dictionary-like collection of unique keys and their values. Also called associative arrays, they are similar to Arrays, but where an Array uses integers as its index, a Hash allows you to use any object type.
[...]
A user-defined class may be used as a hash key if the hash and eql? methods are overridden to provide meaningful behavior.
Note that both hash and eql? are in Object so almost everything you'll come across will have them and so can be a key in a Hash. The default implementations may not be terribly meaningful for some arbitrary object but they'll still be there.
Sometimes generality is easier than artificially limiting your options to only those that the language designer can see a use for. Not even Java is that strict.
I guess what I'm trying to say is that I think you're asking the wrong question. The question you should be asking is:
Why should you be forbidden from using an Array as a Hash key?
This is Ruby where (almost) everything is allowed by default so the answer to that question is that we don't want to artificially limit your options, here's a big pile of possibilities, go do something wonderful and unexpected with it.
If the key has some structure, you may want to directly use that:
{
%w[John Travolta] => :foo,
%w[Olivia Newton John] => :bar,
}
Initial state of Othello/Reversi board
Hash.new(:green).merge{
[4, :d] => :white,
[4, :e] => :black,
[5, :d] => :black,
[5, :e] => :white,
}
From your example it seems like it could be used to more efficiently store large and/or sparse matrices. As you can see, if 3 and 4 both share the same values, they can be "compacted" into a single reference. There may be more formal data structures that would use this, but it's been a while since I used "formal" data structures, so I can't think of any off hand.

Ruby: how to splice an array into a list Lisp-style?

This is something I find myself wanting to do occasionally. Say I have a list of arguments. In Lisp, I can go like
`(imaginary-function ,#args)
in order to call the function with the array turned from one element into the right number of arguments.
Is there similar functionality in Ruby? Or am I just using a completely wrong idiom here?
Yes! It's called the splat operator.
a = [1, 44]
p(*a)
This is the splat operator: function(*list)

Why return an enumerator?

I''m curious about why ruby returns an Enumerator instead of an Array for something that seems like Array is an obvious choice. For example:
'foo'.class
# => String
Most people think of a String as an array of chars.
'foo'.chars.class
# => Enumerator
So why does String#chars return an Enumerable instead of an Array? I'm assuming somebody put a lot of thought into this and decided that Enumerator is more appropriate but I don't understand why.
If you want an Array, call #to_a. The difference between Enumerable and Array is that one is lazy and the other eager. It's the good old memory (lazy) vs. cpu (eager) optimization. Apparently they chose lazy, also because
str = "foobar"
chrs = str.chars
chrs.to_a # => ["f", "o", "o", "b", "a", "r"]
str.sub!('r', 'z')
chrs.to_a # => ["f", "o", "o", "b", "a", "z"]
Abstraction - the fact that something may be an Array is an implementation detail you don't care about for many use cases. For those where you do, you can always call .to_a on the Enumerable to get one.
Efficiency - Enumerators are lazy, in that Ruby doesn't have to build the entire list of elements all at once, but can do so one at a time as needed. So only the number you need is actually computed. Of course, this leads to more overhead per item, so it's a trade-off.
Extensibility - the reason chars returns an Enumerable is because it is itself implemented as an enumerator; if you pass a block to it, that block will be executed once per character. That means there's no need for e.g. .chars.each do ... end; you can just do .chars do ... end. This makes it easy to construct operation chains on the characters of the string.
This completely in accordance with the spirit of 1.9: to return enumerators whenever possible. String#bytes, String#lines, String#codepoints, but also methods like Array#permutation all return an enumerator.
In ruby 1.8 String#to_a resulted in an array of lines, but the method is gone in 1.9.
'Most people think of a String as an array of chars' ... only if you think like C or other languages. IMHO, Ruby's object orientation is much more advanced than that. Most Array operations tend to be more Enumerable like, so it probably makes more sense that way.
An array is great for random access to different indexes, but strings are rarely accessed by a particular index. (and if you are trying to to access a particular index, I suspect you are probably doing school work)
If you are trying to inspect each character, Enumerable works. With Enumberable, you have access to map, each, inject, among others. Also for substitution, there are string functions and regular expressions.
Frankly, I can't think of a real world need for an array of chars.
Maybe a string in ruby is mutable? Then having an Array isn't really an obvious choice - the length could change, for instance. But you will still want to enumerate the characters...
Also, you don't really want to be passing around the actual storage for the characters of a string, right? I mean, I don't remember much ruby (it's been a while), but if I were designing the interface, I'd only hand out "copies" for the .chars method/attribute/whatever. Now... Do you want to allocate a new array each time? Or just return a little object that knows how to enumerate the characters in the string? Thus, keeping the implementation hidden.
So, no. Most people don't think of a string as an array of chars. Most people think of a string as a string. With a behavior defined by the library/language/runtime. With an implementation you only need to know when you want to get nasty and all private with stuff below the abstraction belt.
Actually 'foo'.chars passes each character in str to the given block, or returns an enumerator if no block is given.
Check it :
irb(main):017:0> 'foo'.chars
=> #<Enumerable::Enumerator:0xc8ab35 #__args__=[], #__object__="foo", #__method__=:chars>
irb(main):018:0> 'foo'.chars.each {|p| puts p}
f
o
o
=> "foo"

Why don't more projects use Ruby Symbols instead of Strings?

When I first started reading about and learning ruby, I read something about the power of ruby symbols over strings: symbols are stored in memory only once, while strings are stored in memory once per string, even if they are the same.
For instance: Rails' params Hash in the Controller has a bunch of keys as symbols:
params[:id] or
params[:title]...
But other decently sized projects such as Sinatra and Jekyll don't do that:
Jekyll:
post.data["title"] or
post.data["tags"]...
Sinatra:
params["id"] or
params["title"]...
This makes reading new code a little tricky, and makes it hard to transfer code around and to figure out why using symbols isn't working. There are many more examples of this and it's kind of confusing. Should we or shouldn't we be using symbols in this case? What are the advantages of symbols and should we be using them here?
In ruby, after creating the AST, each symbol is represented as a unique integer. Having symbols as hash keys makes the computing a lot faster, as the main operation is comparison.
Symbols are not garbage collected AFAIK, so that might be a thing to watch out for, but except for that they really are great as hash keys.
One reason for the usage of strings may be the usage of yaml to define the values.
require 'yaml'
data = YAML.load(<<-data
one:
title: one
tag: 1
two:
title: two
tag: 2
data
) #-> {"one"=>{"title"=>"one", "tag"=>1}, "two"=>{"title"=>"two", "tag"=>2}}
You may use yaml to define symbol-keys:
require 'yaml'
data = YAML.load(<<-data
:one:
:title: one
:tag: 1
:two:
:title: two
:tag: 2
data
) #-> {:one=>{:title=>"one", :tag=>1}, :two=>{:title=>"two", :tag=>2}}
But in the yaml-definition symbols look a bit strange, strings looks more natural.
Another reason for strings as keys: Depending on the use case, it can be reasonable to sort by keys, but you can't sort symbols (at least not without a conversion to strings).
The main difference is that multiple symbols representing a single value are identical whereas this is not true with strings. For example:
irb(main):007:0> :test.object_id
=> 83618
irb(main):008:0> :test.object_id
=> 83618
irb(main):009:0> :test.object_id
=> 83618
3 references to the symbol :test, all the same object.
irb(main):010:0> "test".object_id
=> -605770378
irb(main):011:0> "test".object_id
=> -605779298
irb(main):012:0> "test".object_id
=> -605784948
3 references to the string "test", all different objects.
This means that using symbols can potentially save a good bit of memory depending on the application. It is also faster to compare symbols for equality since they are the same object, comparing identical strings is much slower since the string values need to be compared instead of just the object ids.
I usually use strings for almost everything except things like hash keys where I really want a unique identifier, not a string

Resources