Swift Optionals vs. Ruby ||= - ruby

I'm making the transition from learning Ruby to Swift and trying to make any useful associations in order to get a better understanding of similar concepts from both programming languages. I noticed in Swift there are optionals which either have or don't have a value assigned to variables.
var optinalString: String? = "This is optional"
In Ruby we have ||= which from what I understand does something very similar where if the user doesn't assign a value to this variable, then it will use the predefined one that's already been set.
optionalString ||= "This is optional"
Am I on the right track with this assumption? Overall what makes these concepts similar/different?

These two concepts are not equivalent.
In your Swift example, you're creating a variable of type String? and assigning it the value of a string literal. In the Ruby example, you're assigning a string literal to your optionalString variable if optionalString is undefined, nil, or evaluates false (more info).
In Swift, when you create a variable of optional type, all you're doing is specifying that the variable is allowed to be nil, so a closer representation of your Ruby example might look like this:
var optionalString: String?
optionalString = optionalString ?? "This is optional"
Which uses Swift's nil coalescing operator and is equivalent to the following usage of the ternary conditional operator, where optionalString is assigned the unwrapped value of optionalString if it isn't nil, or a fallback value of "This is optional" if it isn't.
optionalString = optionalString != nil ? optionalString! : "This is optional"
Note that by doing this, your variable will still have an optional type and need to be unwrapped to be used, and since you're fallback value is a string literal that won't ever be nil, you can confidently forcibly unwrap the optional with the ! operator.
But even though this can be used to set a variable with a fallback value, it still isn't entirely the same as your Ruby example since all it's doing is checking the nilness of the variable, and not whether it evaluates false or is undefined.
In Swift, you can't test the falseness of variables by sticking them into conditions unless they are instances of a type that conforms to the BooleanType protocol. This means that if you wanted to achieve something similar with a type that supports a falseness check, you could implement something like this:
var optionalBool: Bool? = false
optionalBool = optionalBool != nil ? (!optionalBool! ? true : optionalBool!) : true
Which will assign a fallback value of true to the optionalBool variable if the variable is either nil or evaluates to false. (optionalBool will still need to be unwrapped for most uses)
But this still leaves a difference with undefined variables, and as far as I know, there isn't any way to achieve the equivalence to Ruby's ||= in this regard in Swift without inlining the nilness checks in the instantiation of a variable based on a fallback value and the value of some other variable.
var optionalString: String?
var nonOptionalString = optionalString ?? "This is not optional"
Note, there's no point in nonOptionalString being optional here, since it will always have a value.

Related

Why can you change the value of a local variable in Ruby in a function using another method but not with an assignment operator?

I'm trying to understand the concept of Ruby as a pass-by-reference-value language. Using an example I found on this site...
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name
we get the output "WILLIAM". So value and name are both pointing at the same object, which is initially holding a value of "William" and then .upcase changes it to "WILLIAM". I would understand this as pass-by-reference.
But then if I change .upcase to =:
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
The output becomes "William". Which is pass by value.
Why does an assignment operator make the difference in how a variable is treated in Ruby?
The key here is that you can never change a Ruby object's core self, once it has been created it will always be the same object until garbage collected and destroyed. It is only possible to alter properties of the object.
You can, however, change variables or object references such as instance variables, constants, attr_accessor properties among other things.
So in this case:
def uppercase2(value)
value = "WILLIAM"
end
This reassigns the value local variable. It does nothing to the original object.
If you want to replace that text you need to use methods on the object to effect it, if supported. In this case there is a method:
def uppercase2(value)
value.replace("WILLIAM")
end
These are generally termed in-place modifications as in the object itself is manipulated rather than swapped for another object.
I'm trying to understand the concept of Ruby as a pass-by-reference-value language.
Ruby is pass-by-value. Always. It is never pass-by-reference. The value that is being passed is an immutable unforgeable pointer, but that is very different from pass-by-reference.
C is pass-by-value. And C has pointers. That doesn't mean that if you pass a pointer in C, it magically becomes pass-by-reference. It is still pass-by-value.
C++ has pointers, and it supports both pass-by-value and pass-by-reference. In C++, you can pass pointers by value or by reference and you can pass non-pointers by value or by reference. The two concepts are completely orthogonal.
If we can agree that C is pass-by-value, and we can agree that C has pointers, and we can agree that when we pass a pointer in C, that is still pass-by-value, then we must also agree that Ruby is pass-by-value, because Ruby behaves like a hypothetical version of C, where the only allowed types are "pointer to something", the only way to access a value is dereferencing the pointer, and the only way to pass a value is taking the pointer.
That does not change parameter passing in C in any way, which means it is still pass-by-value, which means if we call that in C pass-by-value, it doesn't make sense to call it anything else in Ruby.
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name
we get the output "WILLIAM". So value and name are both pointing at the same object, which is initially holding a value of "William" and then .upcase changes it to "WILLIAM". I would understand this as pass-by-reference.
Again, this is not pass-by-reference. Pass-by-reference would mean that you can change the reference in the caller's scope, which Ruby does not allow you to do.
This is nothing but simple mutation. Ruby is not a purely functional language, it does allow you to mutate objects. And when you mutate an object, you can observe its changed state regardless of what name you call it.
My friends call me "Jörg" but my barber calls me "Mr. Mittag". When my barber cuts my hair, it doesn't magically grow back when I meet my friends, it will still be gone even though they don't refer to me by the same name as my barber does.
You have two names for the same object, and you mutate that object. You will observe the new state regardless of which name you use to refer to that object.
That is simply "mutable state", it has nothing to do with pass-by-reference.
But then if I change .upcase to =:
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
The output becomes "William". Which is pass by value.
Why does an assignment operator make the difference in how a variable is treated in Ruby?
It doesn't. Both cases are pass-by-value. In the second case, you created a new object and assigned it to the local variable value inside the uppercase2 method. (Technically, it is not a local variable, it is a parameter binding, but it can be rebound inside the method body, precisely because Ruby is pass-by-value. If it were pass-by-reference, then this would have also reassigned the name local variable to the newly created object.)
Sometimes, this specific case of pass-by-value, where the value being passed is an immutable pointer to a potentially mutable object is called call-by-object-sharing, call-by-sharing, or call-by-object. But that is not something different from pass-by-value. It is still pass-by-value. It is a special case of pass-by-value, where the value cannot be "any value" but is always "an immutable unforgeable pointer".
Sometimes, you will hear the description "Ruby is pass-by-value where the value that is being passed is a reference" or "Ruby is pass-by-reference-value" or "Ruby is pass-by-value-reference" or "Ruby is pass-by-object-reference". I don't really like these terms, because they sound very close to "pass-by-reference", but actually the term "reference" in "pass-by-reference" and the term "reference" in "pass-by-object-reference" mean two different things.
In "pass-by-reference", the term "reference" is a technical term that can be thought of as a generalization of the concept of "variable", "storage location", etc. Wheres in "pass-by-value-reference", we are talking about "object references", which are more like pointers but cannot be manufactured or changed.
I also don't like the terms that I used above "pass-by-value where the value being passed is an immutable unforgeable pointer", because the term "pointer" has certain connotations, especially for people coming from C. In C, you can do pointer arithmetic, and you can cast a number to a pointer, i.e. you can "conjure up a pointer out of thin air". You can do none of that in Ruby. That's why I add the adjectives "immutable" (no arithmetic) and "unforgeable" (you cannot create a pointer, only be handed one by the system), but people overlook or ignore them or underestimate their importance.
In some languages, these immutable unforgeable pointers to objects are called "object references" (which is again dangerous because it invites confusion with "pass-by-reference") or OOPS (Object-Oriented PointerS) which has the unfortunate connotations of the mostly unrestricted free-for-all "C" pointers. (Go, for example, has much more restrictive pointers, but when you simply say the word "pointer", nobody thinks of Go.)
Note that none of this is really specific to Ruby. Python, ECMAScript, Java, and many others behave the same way. C# behaves the same way by default, but also supports pass-by-reference as an explicit opt-in. (You must explicitly request pass-by-reference both at the method definition and at the method call.) Scala behaves the same way by default, but optionally supports call-by-name.
C# is actually a very good way of demonstrating the distinctions, because C# supports both pass-by-value and pass-by-reference, both value types and reference types, and obviously, you can write types both as mutable and immutable types, so you actually get all 8 possible different combinations and you can study how they behave.
I came up with this simple test code, which you can easily translate into other languages as well:
def is_ruby_pass_by_value?(foo)
foo.replace('More precisely, it is call-by-object-sharing!')
foo = 'No, Ruby is pass-by-reference.'
end
bar = 'Yes, of course, Ruby *is* pass-by-value!'
is_ruby_pass_by_value?(bar)
p bar
# 'More precisely, it is call-by-object-sharing!'
Here is the slightly more involved example in C#:
struct MutableCell { public string value; }
static void ArgumentPassing(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
ArgumentPassing(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
Let's start breaking this down in something more understandable.
You can compare a variable like name (or value) with a signpost.
Let's say I point it to the a beige house, which will be the value of the variable.
With the above in mind let's take a look at the first example:
# don't worry about this line for now
House = Struct.new(:color)
def color_red(value)
value.color = :red
end
house = House.new(:beige)
color_red(house)
puts house
# prints: #<struct House color=:red>
So what happens here? When we pass house as parameter to color_red Ruby will copy our signpost and assign it to value. Now both signposts point to the same house. We then follow the directions of signpost value and walk to the house and paint it red.
For this reason the color of house will end up being red.
Now let's have a look at the other example:
def color_red(value)
value = House.new(:red)
end
house = House.new(:beige)
color_red(house)
puts house
# prints: #<struct House color=:beige>
Here we start of the same, we copy our signpost house and assign the copy to value. However instead of walking up to the house and painting it, we are going to modify the signpost and point it to a red house somewhere further down the street. And because our signpost value is a copy of house, pointing it in a new direction will not effect house.
Your code is doing the same thing. When you call value.upcase! you are saying to she string. Hey you, upcase all your characters! (Similar to painting the house.)
When you reasign value (value = "WILLIAM") you are essentially just modifying the signpost and pointing it to a new direction. However the signpost is passed as a copy so it does not effect the original.
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name #WILLIAM
In this case, you are mutating the original object. name points to William
and so does value. When you pass in the argument, Ruby will assign
the parameter variable value to the same object that name is pointing to.
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
In this case, you are reassigning value. That is, you are changing which
object value is pointing to. It was pointing to the same string object that
name was pointing to. But, now, you are asking value to reference a
different object.
So, in summary, upcase! mutates the object while = will re-assign.
You can think of 3 circles, value is in one, name in another and William
in the third.
value and name both point to the string object, William.
In the first situation, you mutate the string object that both value and name
are pointing to.
In the second situation, you are creating a 4th circle, which has WILLIAM in it. Then you are erasing the line from value to William and creating a line
from value to WILLIAM.
You get the idea if I do this:
def uppercase2(value)
value = "WILLIAM"
puts value
end
name = 'William'
uppercase2(name) # => “WILLIAM”
puts name # William

Implicitly lazy gather/take not considered a "lazy" object

The documentation for gather/take mentions
Binding to a scalar or sigilless container will also force laziness.
However,
my \result = gather { for 1..3 { take $_² } };
say result.is-lazy # OUTPUT: «False␤»
Same happens if you use a scalar, and binding using := Is there some way to create implicitly lazy gather/take statements?
Update: It's actually lazy, only it does not respond to the is-lazy method in the expected way:
my $result := gather { for 1..3 { say "Hey"; take $_² } };
say $result[0] # OUTPUT: «Hey␤1␤»
So the question is "What are the conditions for is-lazy to consider things actually lazy?"
I think the problem is really that you cannot actually tell what's going on inside a gather block. So that's why that Seq object tells you it is not lazy.
Perhaps it's more a matter of documentation: if is-lazy returns True, then you can be sure that the Seq (well, in fact its underlying Iterator) is not going to end by itself. If is-lazy returns False, it basically means that we cannot be sure.
One could argue that in that case is-lazy should return the Bool type object, which will also be interpreted as being false (as all type objects are considered to be False in boolean context). But that would at least give some indication that it is really undecided / undecidable.

Swift Wrap and Unwrap

I'm a little confused about Swift Wrap and Unwrap! So lets say this is my code:
var name:String? = "FirstName"
print(name)
Does the print function automatically unwrap the name which is optional? so I do not need to say
print(name!) in order to unwrap the name?
I guess what I am trying to understand is these two are equivalent for unwraping an optional variable?
print("name") is just like saying print ("name"!)
The other question I have is about nil.
is saying var name:String? = "FirstName" equivalent to saying var name:String? = nil . So does assigning a nil value wraps a variable?
When something can be nil it can be two things, it can be Some (the value of the given type) or it can be nil.
declaring something like this:
var name: String?
Means that the name variable can be nil, if you assigned a value to it you need to unwrap it to use it.
name = "FirstName"
Now the name variable has been defined, however you still need to ensure it's not nil in some cases, in other cases however (such as when the string doesn't need to be not nil) optional chaining is used.
Optional chaining allows the continuous evaluation of nil or some throughout a statement as long as it's not required to be not nil. If that is the case then you will need to unwrap it:
let someThingRequiresAString = NeedAStringInitializer(string: name!)
In the above statement if name is nil the program will crash, there are several approaches to dealing with things like this, here's a quick example:
if name != nil {
let someThingRequiresAString = NeedAStringInitializers(string: name!)
}
Here you know you can do this b/c name has been evaluated to not be nil. You can also use a nil coalescing operator, or a guard statement. Here's a quick example of nil coalescence in Swift:
let someThingRequiresAString = NeedAStringInit(string: name ?? "New Name")
The optional paradigm is quite powerful and expressive.

Shortcut to avoid checking presence of a hash value twice

I have a hash that may or may not contain a value for a certain key. If it does, I want to transform that value and assign the transformed value to an attribute. If not, I want to set the attribute to nil (or leave it undefined, which in this case has the same effect).
Is there a more concise / idiomatic alternative to the following code?
#my_attr = some_xform(a_hash[:a_key]) if a_hash[:a_key]
I feel like there should be DRY alternative that doesn't require mentioning :a_key twice (i.e., not has_key?[:a_key] either).
(Note that some_xform() is a library method that blows up if it gets nil, which in most cases is the desired behavior -- I don't want to monkey-patch it to silently return nil for nil just to handle this case. Nor is there any default value I can pass that will cause it to return nil.)
Would that work?
#my_attr = if (v = a_hash[:a_key]) then some_xform(v) end
Since you apparently don't need to treat false specially
#my_attr = (v = a_hash[:a_key]) && some_xform(v)
You could do this (although not consider best practice by some):
#my_attr = some_xform(a_hash[:a_key]) rescue nil
Use the short circuting logic of &&:
#my_attr = a_hash[:a_key] && some_xform(a_hash[:a_key])
If a_hash[:a_key] is nil, then && will not evaulate the right hand side, and just return nil.

Is 'x?.y' in Swift the same as 'x?' followed by '.y'?

I understand that in Swift, if I define
var opt:String? = "Optional"
I will get an error if I attempt
opt.isEmpty
since opt is of type String? which does does not have an isEmpty method. And I thought that I understood that
opt?.isEmpty
does not produce an error because opt? unwraps (any non-nil) opt, resulting in a String, which does have an isEmpty method. But
opt?
on its own results in a String? and not a String.
Is ?. a different operator from ? followed by .?
Try
(opt?).isEmpty
and get a suggestive error.
Yes opt?.isEmpty is different from String?.It is called optional chaining.From swift programming guide:
You specify optional chaining by placing a question mark (?) after the
optional value on which you wish to call a property, method or
subscript if the optional is non-nil. This is very similar to placing
an exclamation mark (!) after an optional value to force the
unwrapping of its value. The main difference is that optional chaining
fails gracefully when the optional is nil, whereas forced unwrapping
triggers a runtime error when the optional is nil.
This creates optional as you thinking
var opt:String?
Now
opt?.isEmpty //it will not crash if opt is nil
is same as except
opt!.isEmpty //it will crash if opt is nil
if opt! is nil than it will not crash at runtime.Optional chaining is used to call long sequences of optional without calling.Every optional chain returns optional i.e opt? returns optional unwraps it and if nil than not call isEmpty else call isEmpty and reutns value.
Also
(opt?).isEmpty
When you are writing above statement it is just optional(not optional of optional) and it fails to unwrap because of braces.So error is showing
$T2?? does not have a member named `isEmpty`
to unwrap it use
(opt?)!.isEmpty
it will return false
Edit: To clarify more
var o1 = opt?
var o2 = ((opt?)?)
is doing nothing in its own it just assign same value to o1,o2 i.e String?.
to unwrap opt and o1,o2 they both are optional and need single ! operator to unwrap it.
Also please do not misunderstood between String? and opt? they both are different when ? is used after some type in decleration it makes optional and when ? used after variable optit is used for unwrap in optional chaining and return optional value it is returning
Extra Stuff:
try this to more clarify
(((opt?)?)!).isEmpty //it will unwrap with single !
((((opt?)?)!)?).isEmpty //compiler will show suggestion to remove ?
the below statement makes optional of optional of optional
var opt:String??? = "Optional"
to unwrap
opt!!!.isEmpty
EDIT2
opt? always return optional but if opt is defined as String! it is implicit optional and opt? will return optional(explicit).But if opt is already optional opt? will do nothing
From swift programming guide
To put it another way:
If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining.
If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.
Therefore:
If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
But opt? on its own results in a String? and not a String.
Yes. According to the Swift language reference, Expressions, Postfix Expressions, Optional-Chaining Expression:
On its own, the postfix ? operator simply returns the value of its
argument as an optional.
So putting a ? by itself at the end of an optional is a complete no-op. It has no effect.
Is ?. a different operator from ? followed by .?
Yes. More specifically, ? has the optional-chaining effect when used in any "postfix expression", including when followed by () (function call), . (member access), and [] (subscript).

Resources