What does "#" do in Elixir? - syntax

I have been looking through some coding solutions and they show the "#" symbol; however, I can't really seem to figure out what that symbol does by looking through documentation.
What does the # symbol do in Elixir, and why is it important?
Here is an example:
defmodule RNATranscription do
#dna_nucleotide_to_rna_nucleotide_map %{
# `G` -> `C`
71 => 67,
# `C` -> `G`
67 => 71,
# `T` -> `A`
84 => 65,
# `A` -> `U`
65 => 85
}
#doc """
Transcribes a character list representing DNA nucleotides to RNA
## Examples
iex> RNATranscription.to_rna('ACTG')
'UGAC'
"""
#spec to_rna([char]) :: [char]
def to_rna(dna) do
dna
|> Enum.map(&get_rna_for_dna/1)
end
defp get_rna_for_dna(dna_nucleotide) do
#dna_nucleotide_to_rna_nucleotide_map[dna_nucleotide]
end
end

It's the syntax for a module attribute:
Module attributes in Elixir serve three purposes:
They serve to annotate the module, often with information to be used by the user or the VM.
They work as constants.
They work as a temporary module storage to be used during compilation.
Attributes are read by the compiler at compile-time, so they cannot be accessed or changed at runtime. At runtime, they will have been replaced with whatever was evaluated by the compiler.
In your case, this function:
defp get_rna_for_dna(dna_nucleotide) do
#dna_nucleotide_to_rna_nucleotide_map[dna_nucleotide]
end
Is effectively compiled to this:
defp get_rna_for_dna(dna_nucleotide) do
%{
71 => 67,
67 => 71,
84 => 65,
65 => 85
}[dna_nucleotide]
end
#spec is used to define typespecs, #doc is for documentation.

The # symbol in Elixir denotes module attributes, which are useful compile-time settings. You often see them in places where you might put class constants in an OO language.
However, module attributes are more subtle than what you might find in an OO language. Here are some important takeaways:
They do not use the = to assign a value (as you might be in the habit of doing if you are used to defining class constants in OO-land). The syntax is more like function input where the optional parentheses are dropped.
Module attributes can be redefined multiple times throughout the module. You'll see this frequently with #doc attributes that annotate the function that follows it, with #spec which annotates the function input/output, or inside tests with #tag to change the inputs to the test that follows it. This can offer a useful way to put big values out of the way of the function logic to improve readability.
Module attributes can be accumulated. Normally, each instance of an attribute reassigns its value, but if you set accumulate: true when you register the attribute, then subsequent definitions will accumulate so that reading the attribute will return all the accumulated values. From the doc page:
defmodule MyModule do
Module.register_attribute(__MODULE__, :custom_threshold_for_lib, accumulate: true)
#custom_threshold_for_lib 10
#custom_threshold_for_lib 20
#custom_threshold_for_lib #=> [20, 10]
end
Module attributes are evaluated at compile-time. Because they can raise visibility on important module-wide values, you might be tempted to do something like stash an ENV value:
defmodule Trouble do
#my_value System.fetch_env("BOOM") # <-- don't do this!
end
More recent versions of Elixir will show warnings if you attempt to do this (and some values, e.g. captured functions, will raise an error), so as a general rule of thumb, it's best to keep the module attributes simple and static.

Related

How to use value of a string to refer to variables?

Some programmer made a method that gets lots of arguements like this:
def age_entry(age_1, age_2, age_3, age_4, age_5, age_6, age_7, age_8)
end
They could pass an array but simply they didn't. I love automation and hate to repeatedly add these variables to and array like this
ages = [age_1, age_2, age_3 ,..., age_8]
I would like to use metaprogramming or other ways to loop with a for or each methods to add them variables to an array like this:
(1..8).each do |index| do
ages << "age_" + index #value of age_[index] get saved to ages
end
P.S. I know I can use copy and paste but this is only for doing automation stuff with Ruby.
"Some programmer" should remember that you can pass in arrays. This sort of method signature is really obnoxious to work with for a multitude of reasons, some of them you've already discovered.
One way to refactor this method and preserve functionality is to just take in varargs:
def age_entry(*ages)
end
Now those values are put in an array for you but you can call the method the same way as before. As a plus you can specify more or fewer entries.
Variables with names like x1, x2 and so on are violations of the Zero, One or Infinity Rule and are a sign you need to think about the problem differently.
You don’t need any metaprogramming here. Just splat them:
ages = [age_1, age_2, age_3 ,..., age_8]
# ⇓ HERE
age_entry(*ages)
If you want to collect age_(1..8) into the array, assuming all local vars are defined, use Kernel#binding:
b = binding
ages = (1..8).map { |i| b.local_variable_get("age_#{i}") }
Suppose the method is as follows.
def oldest(age_bill, age_barb, age_trixie)
puts "Barb is #{age_barb} years old"
[age_bill, age_barb, age_trixie].max
end
oldest(35, 97, 29)
#=> 97
As well as the calculation in the penultimate line (which the OP wishes to avoid), this method requires knowledge of an individual method argument (age_barb). The following is one way to accomplishing both requirements.
def oldest(age_bill, age_barb, age_trixie)
puts "Barb is #{age_barb} years old"
b = binding
args = method(__method__).parameters.map { |arg| b.local_variable_get(arg[1]) }
args.max
end
#=> 97
Barb is 97 years old
Here
args
#=> [35, 97, 29]

Custom Methods for Treetop Syntax Nodes

I have a Treetop PEG grammar that matches some keys. I want to look up the values associated with those keys in a hash I give the parser. How can I make it so that the syntax nodes have access to methods or variables from the parser?
For example, here's a simple grammar that finds a single word and tries to look up its value:
# var.treetop
grammar VarResolver
include VarLookup
rule variable
[a-zA-Z] [a-zA-Z0-9_]*
{
def value
p found:text_value
find_variable(text_value)
end
}
end
end
Here's a test file using it:
# test.rb
require 'treetop'
module VarLookup
def set_variables(variable_hash)
#vars = variable_hash
end
def find_variable(str)
#vars[str.to_sym]
end
end
Treetop.load('var.treetop')
#p = VarResolverParser.new
#p.set_variables name:'Phrogz'
p #p.parse('name').value
Running this test, I get the output:
{:found=>"name"}
(eval):16:in `value': undefined method `find_variable'
for #<Treetop::Runtime::SyntaxNode:0x00007f88e091b340> (NoMethodError)
How can I make find_variable accessible inside the value method? (In the real parser, these rules are deeply nested, and need to resolve the value without returning the actual name to the top of the parse tree. I cannot just return the text_value and look it up outside.)
This is a significant weakness in the design of Treetop.
I (as maintainer) didn't want to slow it down further by
passing yet another argument to every SyntaxNode,
and break any custom SyntaxNode classes folk have
written. These constructors get the "input" object, a Range
that selects part of that input, and optionally an array
of child SyntaxNodes. They should have received the
Parser itself instead of the input as a member.
So instead, for my own use (some years back), I made
a custom proxy for the "input" and attached my Context
to it. You might get away with doing something similar:
https://github.com/cjheath/activefacts-cql/blob/master/lib/activefacts/cql/parser.rb#L203-L249

Ruby—integer substring (subbit?)

Substrings work where "hello"[0..2] returns "hel"
Is there an integer equivalent, that returns the sub-bits, as in 9[1..3] returns 4 or "100"?
Context:
I'm trying to do a genetic algorithm, and there is a cross over stage where you split two chromosomes in two, then swap halves, e.g. "10101010" crossed with "00000000" at i = 4 would be "00001010", "10100000"
However, I'm doing this a few million times, so using strings is inefficient, so is there a bitwise way to do this?
You might consider refining the class Fixnum to permit Fixnum#[]'s argument to be either a bit index or a range of bit indices.
module StabBitRange
def [](arg)
case arg
when Range
mask = arg.reduce(0) { |n, idx| n |= (1 << idx) }
(self & mask) >> arg.first
else
super
end
end
end
module StabBits
refine Fixnum do
prepend StabBitRange
end
end
See Refinements and Module#prepend. Prepend StabBitRange moves the methods contained therein (here just one) before the methods with the same names in Fixnum in the ancestor chain. The alternative (commonly used before Prepend was introduced in Ruby v2.0) is to alias Fixnum#[] and then redefine Fixnum[] to be the new method that takes either a bit index or a range of bit indices. (See the edit history of this answer to see how that is done.) I expect readers will agree that Prepend is a more sensible way of doing that.
To make this code available for use we need only invoke the keyword using.
using StabBits
n = 682
n.to_s(2) #=> "1010101010"
n[0] #=> 0
n[1] #=> 1
n[2] #=> 0
n[0..7] #=> 170 170.to_s(2) => "10101010"
n[1..7] #=> 85 85.to_s(2) => "1010101"
n[2..6] #=> 10 10.to_s(2) => "1010"
When StabBitRange#\[\] is called and the argument is not a range, super invokes Fixnum#[] and passes the argument. That method handles argument errors as well as returning the desired bit when there are no errors.
When this code is run in IRB, the following exception is raised: RuntimeError: main.using is permitted only at top level. That's because IRB is running at the top level, but code run within IRB is running at a higher level from the perspective of the Ruby parser. To run this in IRB it is necessary to enclose using StabBits and the code following in a module.

Understanding Implicit hash within a ruby method definition

I was watching the CooperPress Youtube video that discusses different ways to specify arguments with defaults within a method definition.
He discusses how in Ruby 2.0 there is some syntactic sugar which allows you to specify an implicit hash that also sets default values for each key within this hash. Located at this part of the video, but I will redisplay the code below:
def some_method(x: 10, y: 20, z: 30)
puts x
puts y
puts z
end
some_method x: 1, y: 2
=> 1
=> 2
=> 30
What I am having trouble understanding is why turning that implicit hash into an explicit hash doesn't work. Basically: all I am doing is putting curly braces around that implicit hash argument within the method definition. As I see it: putting curly braces around the key/values is just a more explicit way to say that a hash wraps those key/values and it should have the exact same behavior. However, when I do this it errors out:
def some_method({x: 10, y: 20, z: 30}) #curly braces here
puts x
puts y
puts z
end
some_method x: 1, y: 2
=> rb:1: syntax error, unexpected {, expecting ')' def some_method({x: 10, y: 20, z: 30})
Question: Why does turning that implicit hash argument within the method definition into an explicit hash argument make the method error out?
Haven't watched that video, but "implicit hash" is a poor choice of words. This is a feature called "keyword arguments" and it has a pretty specific syntax which, yes, resembles a hash, but isn't one.
For example, it allows required arguments, which is impossible in a hash.
def foo(required:, optional: 1)
# some code
end
There are special syntax rules for what you can write in a method argument definition, you cannot just write arbitrary expressions.
You could write this:
def foo(opts = arbitrary_hash)
That would mean the method has one argument and its default value is whatever arbitrary_hash is, but that would be an unusual way to do it because then if you pass any argument to the method, none of the defaults get applied.

What is the # (sharp, number, pound, hash) sign used for in Ruby?

What are the various meanings of the Ruby sharp/number sign/pound/hash(#) symbol
How many contexts does the symbol # in Ruby have ?
I know that #` represents comment
# a comment
or 'convert to the value':
i = 1
print "#{i}" # simple example
However I also see some Ruby docs describe built-in methods like these:
Array#fill
File::file?
Why do they describe the same thing using 2 different symbols ?
I am new in Ruby. Thanks
This is how instance method described:
Array#fill
So you can:
a = Array.new(2)
=> [nil, nil]
a.fill(42)
=> [42, 42]
This is how class method described:
String::new
s = String.new('abc')
=> "abc"
In Perl, # is used for commenting, and since Perl is an 'ancestor' of Ruby, the role was carried over.
The "#{}" syntax is called 'interpolation' and the pound was picked most likely because interpolation is similar in a sense to commenting, because you are changing the context of your code (in this case to another context for execution)
The # following a Class name is just meant to indicate the following identifier is a method of that Class, and is just a convention. Read more about it here: Why are methods in Ruby documentation preceded by a hash sign?
The :: is interesting, it acts similarly to the . in that you can call methods via both
Car::is_hybrid?
and
car.is_hybrid?
As you will see in most code though . is preferred for methods.
One case where :: is often preferred is where you have constant in the class and you will see this in system calls such as Math::PI or ones you create, e.g. ThePentagon::NUMBER_OF_BUILDING_SIDES
Just to show you as an example,that Ruby shows instance method preceded with the symbol # and class methods preceded with the symbol ..
class Foo
def self.foo;end
def bar;end
end
p Foo.method(:foo) # => #<Method: Foo.foo>
p Foo.new.method(:bar) # => #<Method: Foo#bar>

Resources