Eiffel: type casting operators whats the difference between ~ / and attached statements? - eiffel

Whats the difference between
object test
if attached {DOG} an_animal as a_dog then
a_dog.eat (meat)
end
operator / of the class TYPE
if an_animal / a_dog then
an_animal.eat (food)
end
reference equality =
if a_dog = an_animal then
a_dog.eat (meat)
else
an_animal.eat (food)
end
object equality ~
if a_dog ~ an_animal then
a_dog.eat (meat)
else
an_animal.eat (food)
end
And where can I find documentation about that?

The main differences among the constructs are in operand types and semantics.
An object test allows for figuring out whether a particular expression evaluates to a value conforming to a particular type. The value of the conforming object can be retrieved via an associated object test local.
The operator / of the class TYPE returns the value of the passed argument, if it conforms to the type specified by the type object. Otherwise, it returns Void for a reference type and a default value for an expanded type. This is quite similar to object test, but has minor differences. Essentially, the expression {SOME_TYPE} / expression is equivalent to
if attached {SOME_TYPE} expression as value then
value
else
{detachable SOME_TYPE}.default
end
For reference types, the object test attached {SOME_TYPE} expression as value is equivalent to
attached ({SOME_TYPE} / expression) as value
But there is no equivalent for expanded types.
The main use of the operator / is to obtain a value of a specific type if possible or Void otherwise:
x := {SOME_TYPE} / expression
Reference equality = compares (most of the time) object references and has nothing to do with their types. In other words, a = b for reference objects means that a and b are aliases. If one of the operands is an expanded object, = is the same as object equality (see below).
If the expression dog = animal returns True, the variables dog and animal reference the same object, but we have no idea what type it is.
Object equality ~ compares contents of two objects. First, it checks that both are non-void, have the same type, and then invokes a (user-defined) predicate is_equal to get the result of the operator.
If the expression dog ~ animal returns True, the variables dog and animal could be the same or different objects that have the same type and are equal (according to is_equal). As in the previous case, we have no idea what type they are.
1, 3 and 4 are documented in the language standard, 2 is a feature of the class TYPE (with the corresponding name attempted).

Related

twin vs deep_twin, is_equal vs is_deep_equal

What is the difference between twin and deep_twin which implies (and ensures) the difference between is_equal and is_deep_equal in eiffel?
twin makes a copy of the current object. If the object references other objects, by default it does not make copies of these other objects. That's why it is said that the function makes a "shallow" copy. On the contrary, deep_twin makes a copy not only of the current object, but also (recursively) copies of all other objects that are referenced by the current one. Here is an example
class A create make feature
make (value: STRING) do item := value end
item: STRING
end
a: A
...
a.item = a.twin.item -- Evaluates to True
a.item = a.deep_twin.item -- Evaluates to False
In the first comparison, the value of item in the twin is the same string object as in the original object. In the second comparison, the value of item in the twin is a new string object, equal to a.item. In other words, if a.item = s, then a.twin.item = s, but a.twin.item = s1 where s1 /= s, but s1 ~ s.
is_equal and is_deep_equal are conterparts for the functions above. The first makes a "shallow" equality test, the second — a deep one. In the example, we have
a.is_equal (a.twin) -- Evaluates to True
a.is_deep_equal (a.twin) -- Evaluates to True
a.is_equal (a.deep_twin) -- Evaluates to False
a.is_deep_equal (a.deep_twin) -- Evaluates to True
If objects are "shallow" equal, they are also "deep" equal. But the reverse is not true.
All the above is valid with the assumption that the default versions of is_equal and twin are used. The features can be redefined to go deeper. For the class above we can add
is_equal (other: like Current): BOOLEAN
do
-- The default version is "Result := item = other.item"
Result := item ~ other.item -- Compare content rather than references
end
copy (other: like Current) -- twin is defined in terms of this procedure
do
-- The default version is "item := other.item"
item := other.item.twin -- Use a copy instead of the reference
end
With this redefinition, twin/deep_twin and is_equal/is_deep_equal become almost the same.

Perl: Length of an anonymous list

How to get the length of an anonymous list?
perl -E 'say scalar ("a", "b");' # => b
I expected scalar to return the list in a scalar context - its length.
Why it returns the second (last) element?
It works for an array:
perl -E 'my #lst = ("a", "b"); say scalar #lst;' # => 2
You can use
my $n = () = f();
As applied to your case, it's
say scalar( () = ("a", "b") );
or
say 0+( () = ("a", "b") );
First, let's clear up a misconception.
You appear to believe that some operators evaluate to some kind of data structure called a list regardless of context, and that this list returns its length when coerced into scalar context.
All of that is incorrect.
An operator must evaluate to exactly one scalar in scalar context, and a sub must return exactly one scalar in scalar context. In list context, operators can evaluate to any number of scalars, and subs can return any number of scalars. So when we say an operator evaluates to a list, and when we say a sub returns a list, we aren't referring to some data structure; we are simply using "list" as a shorthand for "zero or more scalars".
Since there's no such thing as a list data structure, it can't be coerced into a scalar. Context isn't a coercion; context is something operators check to determine to what they evaluate in the first place. They literally let context determine their behaviour and what they return. It's up to each operator to decide what they return in scalar and list context, and there's a lot of variance.
As you've noted,
The #a operator in scalar context evaluates to a single scalar: the length of the array.
The comma operator in scalar context evaluates to a single scalar: the same value as its last operand.
The qw operator in scalar context evaluates to a single scalar: the last value it would normally return.
On to your question.
To determine to how many scalars an operator would evaluate when evaluated in list context, we need to evaluate the operator in list context. An operator always evaluates to a single scalar in scalar context, so your attempts to impose a scalar context are ill-founded (unless the operator happens to evaluate to the length of what it would have returned in list context, as is the case for #a, but not for many other operators).
The solution is to use
my $n = () = f();
The explanation is complicated.
One way
perl -wE'$len = () = qw(a b c); say $len' #--> 3
The = () = "operator" is a play on context. It forces list context on its right side and assigns the length of the list. See this post about list vs scalar assignments and this page for some thoughts on all this.
If this need be used in a list context then the LHS context can also be forced by scalar, like
say scalar( () = qw(a b c) );
Or by yet other ways (0+...), but scalar is in this case actually suitable, and clearest.
In your honest attempt scalar imposes the scalar context on its operand -- or here an expression, which is thus evaluated by the comma operator, whereby one after another term is discarded, until the last one which is returned.
You'd get to know about that with warnings on, as it would emit
Useless use of a constant ("a") in void context at -e line 1
Warnings can always be enabled in one-liners as well, with -w flag. I recommend that.
I'd like to also comment on the notion of a "list" in Perl, often misunderstood.
In programming text a "list" is merely a syntax device, that code can use; a number of scalars, perhaps submitted to a function, or assigned to an array variable, or so. It is often identified by parenthesis but those really only decide precedence and don't "make" anything nor give a "list" any sort of individuality, like a variable has; a list is just a grouping of scalars.
Internally that's how data is moved around; a "list" is a fleeting bunch of scalars on a stack, returned somewhere and gone.
A list is not -- not -- any kind of a data structure or a data type; that would be an array. See for instance a perlfaq4 item and this related page.
Perl references are hard. I'm not sending you to read prelref since it's not something that anyone can just read and start using.
Long story short, use this pattern to get an anonymous array size: 0+#{[ <...your array expression...> ]}
Example:
print 0+#{[ ("a", "b") ]};

Swift predicate only matches first value in array of values

I have a class Download that serves as a wrapper for CKQueryOperation. One of the inits allows me to build my predicate with an array of values:
init(type: String, queryField: String, queryValues: [CKRecordValue], to rec: RecievesRecordable, from database: CKDatabase? = nil) {
let predicate = NSPredicate(format: "\(queryField) = %#", argumentArray: queryValues)
query = CKQuery(recordType: type, predicate: predicate)
reciever = rec
db = database
super.init()
}
When I test it, query only matches the first value in the array. So if queryValues = [testValue0, testValue1] and I have one record whose field matches testValue0 and I have a second record that matches testValue1, only the first record will be discovered. If I switch the order, than the other record gets recognized.
It seems weird that I can create a predicate with an array but only the first value gets matched. The documentation says that values are substituted in the order they appear, but shouldn't it still be moving on to the second value?
For more context, each record is stored in a separate database (private vs public) and my Download class launches two separate CKQueryOperations that both rely on query, if database param is left nil. Whichever op fails ends up finding no results that match the first value and then giving up before checking the second value.
I can include the full code for 'Download' and my failing unit test if needed.
You are using the wrong predicate. You want to use the IN operation. And instead of using string substitution for the field name, use the %K format specifier:
let predicate = NSPredicate(format: "%K IN %#", arguments: queryField, queryValues)
Note that the NSPredicate(format:argumentArray:) expects there to be one format specifier in the format string for each value in the argument array. Since your format only had one format specifier, only the first value was taken from the array. And since you used =, the field was simply compared against that one value.
Basic Comparisons
=, == The left-hand expression is equal to the right-hand expression.
=, => The left-hand expression is greater than or equal to the right-hand expression. <=, =< The left-hand expression is less than or
equal to the right-hand expression.
The left-hand expression is greater than the right-hand expression. < The left-hand expression is less than the right-hand expression. !=,
<> The left-hand expression is not equal to the right-hand expression.
String Comparisons
BEGINSWITH The left-hand expression begins with the right-hand
expression.
CONTAINS The left-hand expression contains the right-hand expression.
ENDSWITH The left-hand expression ends with the right-hand expression.
LIKE The left hand expression equals the right-hand expression: ? and
are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters.
MATCHES The left hand expression equals the right hand expression
using a regex-style comparison according to ICU v3 (for more details
see the ICU User Guide for Regular Expressions).
I used Basic Comparisons
let resultPredicate = NSPredicate(format: "%K = %#", "key", "value")
let result_filtered = MYARRAY.filtered(using: resultPredicate) as NSArray
More information : Predicate Programming Guide

Perl structures and assignment

In perldata, I found the following examples and explanations.
#foo = ('cc', '-E', $bar);
assigns the entire list value to array #foo, but
$foo = ('cc', '-E', $bar);
assigns the value of variable $bar to the scalar variable $foo.
This really confuses me, so $foo is equivalent to $bar? How to understand the difference between #foo and $foo
The examples in perldata:
#foo = ('cc', '-E', $bar);
$foo = ('cc', '-E', $bar);
Because #foo creates a list context, all the values in the parens are assigned to #foo. $foo on the other hand is a scalar, and so is only assigned the last element in the list, because it is in scalar context.
It is equal to saying:
'cc', '-E';
$foo = $bar;
In Perl, a scalar, like $foo, can only hold a single value, and so the rest of the list is simply discarded. An array, like #foo will slurp as many values as the list holds.
In Perl, it is allowed to have the same name on variables of different types. #foo and $foo will be considered two different variables.
Expressions are allowed to have different meanings depending on which context they're evaluated in. The three main contexts are list, scalar, and void, though there exists several subcontexts of scalar context (boolean, string, and numeric being the most important ones).
The comma operator is no exception to this rule. In list context, the comma operator acts as a list concatenation operator, evaluating its operands in list context and combining the resulting lists into a single list. This is likely the context you're familiar with when dealing with the comma operator.
However, in scalar context, the comma operator functions much like the comma operator in C; it evaluates a sequence of expressions and discards their results, except for the rightmost expression which it returns (as a side note, the expressions that are discarded are evaluated in void context, and the expression that's returned is evaluated in scalar context). To learn how each of the perl operators behave in different contexts, I suggest reading perlop.
In order to fully understand context, you have to realize that the outermost operator enforces a context on its operands, whose operators then enforce a context on their operands, and so on (another side note: the outermost expression of a line is always evaluated in void context). So, for example, when the assignment operator is being used with an array or hash variable (beginning with a % or #), the right-hand side of the assignment is consequently evaluated in list context. If the variable is a scalar, however, the right-hand side of the assignment is evaluated in scalar context instead. This is why the comma operators in the assignments below:
#foo = ('cc', '-E', $bar);
$foo = ('cc', '-E', $bar);
act in completely different ways.
For more information on how you can write code that controls or reacts to context, read about the scalar and wantarray operators.

Why doesn't ||= work with arrays?

I use the ||= operator to provide default values for variables, like
$x ||= 1;
I tried to use this syntax with an array but got a syntax error:
#array||= 1..3;
Can't modify array dereference in logical or assignment (||=) ...
What does it mean and how should I provide arrays with default values?
Because || is a scalar operator. If #array||= 1..3; worked, it would evaluate 1..3 in scalar context, which is not what you want. It's also evaluating the array in scalar context (which is ok, because an empty array in scalar context is false), except that you can't assign to scalar(#array).
To assign a default value, use:
#array = 1..3 unless #array;
But note that there's no way to tell the difference between an array that has never been initialized and one that has been assigned the empty list. It's not like a scalar, where you can distinguish between undef and the empty string (although ||= doesn't distinguish between them).
eugene y found this perl.perl5.porters message (the official Perl developers' mailing list) that goes into more detail about this.
This page has a good explanation, imho:
op= can occur between any two
expressions, not just a var and an
expression, but the left one must be
an lvalue in scalar context.
Since #x ||= 42 is equivalent to
scalar(#x) = #x || 42, and you aren't
allowed to use scalar(#x) as an
lvalue, you get an error.

Resources