twin vs deep_twin, is_equal vs is_deep_equal - eiffel

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.

Related

Lua How iterators and for loops are work, what is it?

How does it work and why does the loop return values for k, v vars in order?
Why if I just call the next() function many times it does not return the same result as in the loop?
Where does the for loop get the values for the second argument of the next() function?
I don't understand how it works
local t = {'a', 'b', 'c'}
-- prints 1 a, 2 b, 3 c
for k, v in next, t, nil do
print(k, v)
end
print()
print(next(t)) -- 1 a
print(next(t)) -- why not 2 b?
print(next(t)) -- why not 3 c?
I don't understand much there https://www.lua.org/pil/7.html, I asked a question. How it works in lua - iterators, for loops, closures
next is a stateless iterator. That is, next is a pure function - its return values are determined only by its inputs (the invariant state: the table & the loop control variable: the key)
This explains why
print(next(t)) -- 1 a
print(next(t)) -- why not 2 b?
print(next(t)) -- why not 3 c?
must print 1 a three times: Each time, you call next with the table as first (and nothing as second argument). If the second argument to next is nil or nothing, next returns the first key-value pair of the given table. To get the next k-v-pair, you need to pass that key to next: next(t, 1) may give you 2 b. To fix your subsequent calls to next, you need to always pass the last key to get the next k-v-pair:
local k, v = next(t)
print(k, v) -- 1st entry
k, v = next(t, k)
print(next(t, k)) -- 2nd entry
k, v = next(t, k)
print(next(t, k)) -- 3rd entry
note that it is not guaranteed that next traverses the list part of a table in order (although all implementations do it this way)
As outlined in the PIL chapter 7.2, a for-loop is just syntactic sugar to iterate over such an iterator (for the sake of simplicity, we assume every iterator returns two values like next):
for k, v in next, t, nil do
print(k, v)
end
is equivalent to
local iterator_func, invariant_state, control_var = next, t, nil
while true do
local k, v = iterator_func(invariant_state, control_var)
if k == nil then break end
print(k, v)
control_var = k
end
pairs(t) is just even more sugar for next, t, nil (which may also be written as next, t). You can trivially implement pairs yourself as function pairs() return next, t, nil end. ipairs works similarly, except it doesn't use next but an "inext" iterator which only considers integer keys (and guarantees inorder traversal).
Stateful iterators on the other hand usually have a hidden state (usually upvalues of a closure). Every call to the iterator function changes the hidden state; the invariant state and loop control variable usually is not needed at all (and ignored entirely). These iterators behave as you would expect. We can write a stateful pairs (that is, a pairs which always returns a closure remembering the current position of the "cursor" in the table) as follows by making the current key an upvalue:
function stateful_pairs(t)
local key
-- This is the iterator function: Note how we may take no params
-- since we have everything as an upvalue already
return function()
local value
key, value = next(t, key)
return key, value
end
end
this now works the way you expected in your example, because the closure returned by this pairs remembers its state in upvalues:
local stateful_next = stateful_pairs(t)
print(stateful_next(t)) -- 1 a
print(stateful_next(t)) -- 2 b
print(stateful_next(t)) -- 3 c
and you can still use this in a for-loop. For stateful iterators without parameters, a for loop is just syntactic sugar for calling a function until it returns nil:
for k, v in stateful_pairs(t) do
print(k, v)
end
Lua has a few stateful iterators such as io.lines or string.gmatch in its standard library; making them stateless would require a very ugly loop control variable & invariant state.

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

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).

Odd "Check_VIOLATION" failed test case in Eiffel

The main issue from the below picture is that when "check Result end" statement is added it automatically fails and displays "CHECK_VIOLATION" error in debugger.
Also, the HASH_TABLE doesn't store all items given to it but I fixed that by switching HASH_TABLE[G, INTEGER] instead of using the current HASH_TABLE[INTEGER, G]
My main problem is why does it throw Check_violation always and fail whenever a "check result end" statement is seen? Maybe the HAS[...] function is bad?
Currently any test case feature with "check result end" makes it false and throw CHECK_VILOATION
code:
class
MY_BAG[G -> {HASHABLE, COMPARABLE}]
inherit
ADT_BAG[G]
create
make_empty, make_from_tupled_array
convert
make_from_tupled_array ({ARRAY [TUPLE [G, INTEGER]]})
feature{NONE} -- creation
make_empty
do
create table.make(1)
end
make_from_tupled_array (a_array: ARRAY [TUPLE [x: G; y: INTEGER]])
require else
non_empty: a_array.count >= 0
nonnegative: is_nonnegative(a_array)
do
create table.make(a_array.count)
across a_array as a
loop
table.force (a.item.y, a.item.x)
end
end
feature -- attributes
table: HASH_TABLE[INTEGER, G]
counter: INTEGER
testing code:
t6: BOOLEAN
local
bag: MY_BAG [STRING]
do
comment ("t6:repeated elements in contruction")
bag := <<["foo",4], ["bar",3], ["foo",2], ["bar",0]>> -- test passes
Result := bag ["foo"] = 5 -- test passes
check Result end -- test fails (really weird but as soon as check statement comes it fails)
Result := bag ["bar"] = 3
check Result end
Result := bag ["baz"] = 0
end
Most probably ADT_BAG stands for an abstraction of a multiset (also called a bag) that allows to keep items and to tell how many items equal to the given one are there (unlike a set, where at most one item may be present). If so, it is correct to use HASH_TABLE [INTEGER, G] as a storage. Then its keys are the elements and its items are the elements numbers.
So, if we add the same element multiple times, its count should be increased. In the initialization line we add 4 elements of "foo", 3 elements of "bar", 2 elements of "foo" again, and 0 elements of "bar" again. As a result we should have a bag with 6 elements of "foo" and 3 elements of "bar". Also there are no elements "baz".
According to this analysis, either initialization is incorrect (numbers for "foo" should be different) or the comparison should be done for 6 instead of 5.
As to the implementation of the class MY_BAG the idea would be to have a feature add (or whatever name specified in the interface of ADT_BAG) that
Checks if there are items with the given key.
If there are none, adds the new element with the given count.
Otherwise, replaces the current element count with the sum of the current element count and the given element count.
For simplicity the initialization procedure would use this feature to add new items instead of storing items in the hash table directly to process repeated items correctly.

Post-Condition Violation with Feature in Eiffel

This is part of the class. This class is called BAG[G -> {HASHABLE, COMPARABLE}]
it inherits from ADT_BAG which has deferred features such as count, extend, remove, remove_all, add_all... more, and domain to be re-implemented.
domain returns ARRAY[G] which is a sorted array list of G
i always get Post-condition violation "value_semantics" which is something to do with object comparison but I checked and there is no code for object comparison which is very weird.
I tried to remake the code for domain feature several times and it ALWAYS ends up with a post-condition violation or a fail.
When I check the debugger the array "a" that is returned from domain always has count 0 but this does not make sense because i move keys from table to "a" but count is still 0.
Maybe I am transferring the keys wrong to the array?
code:
count: INTEGER
-- cardinality of the domain
do
result := domain.count -- has to be domain.count because loop invariant: consistent: count = domain.count
end
domain: ARRAY[G]
-- sorted domain of bag
local
tmp: G
a: ARRAY[G]
do
create a.make_empty
across 1 |..| (a.count) as i -- MOVING keys from table to array
loop
across table as t
loop
if not a.has (t.key) then
a.enter (t.key, i.item)
i.forth
end
end
end
across 1 |..| (a.count-1) as i -- SORTING
loop
if a[i.item] > a[i.item+1] then
tmp := a[i.item]
a[i.item] := a[i.item+1]
a[i.item+1] := tmp
end
end
Result := a
ensure then
value_semantics: Result.object_comparison -- VIOLATION THROWN HERE
correct_items: across 1 |..| Result.count as j all
has(Result[j.item]) end
sorted: across 1 |..| (Result.count-1) as j all
Result[j.item] <= Result[j.item+1] end
end
test code:
t3: BOOLEAN
local
sorted_domain: ARRAY[STRING]
do
comment("t3:test sorted domain")
sorted_domain := <<"bolts", "hammers", "nuts">>
sorted_domain.compare_objects
Result := bag2.domain ~ sorted_domain -- fails here
check Result end
end
The first loop across 1 |..| (a.count) as i is not going to make a single iteration because a is empty (has no elements) at the beginning. Indeed, it has been just created with create a.make_empty.
Also, because keys in the table are unique it is useless to check whether a key has been added to the resulting array: the test not a.has (t.key) will always succeed.
Therefore the first loop should go over keys of a table and add them into the resulting array. The feature {ARRAY}.force may be of interest in this case. The addition of the new elements should not make any "holes" in the array though. One way to achieve this is to add a new element right after the current upper bound of the array.
The sorting loop is also incorrect. Here the situation is reversed compared to the previous one: sorting cannot be done in a single loop, at least two nested loops are required. The template seems to be using Insertion sort, its algorithm can be found elsewhere.
EDIT: the original answer referred to {ARRAY}.extend instead of {ARRAY}.force. Unfortunately {ARRAY}.extend is not generally available, but a.extend (x) would have the same effect as a.force (x, a.upper + 1).

Operator # nil values at end of array

I use:
b.x = {}
a = Obj()
a:AddParams("a", "b", "c")
...
...
function Obj:AddParams(a, b, c, d, e)
table.insert(b.x, {["one"] = a, ["two"] = b, ["three"] = c, ["four"] = d, ["five"] = e})
end
and then I print #b.x and it prints 1. Shouldn't it print 2 since # operator counts nil values and I only give the first 3 parametrers on a:AddParams, leaving the last two nil? Thanks a lot
Shouldn't it print 2 since # operator counts nil values
No, exactly the opposite!
First of all, the whole notion of adding a nil to a table is invalid. You can store anything in a table except nil. Doing so simple deletes the value already present in that key (index) but doesn't insert a nil inside. It's like the mathematical null set ∅ which is used to denote emptiness as an entity but is not a tangible value/object. Accessing any index not present in the table would give you nil, you don't have to insert one to see them being there; any non-existent key has the value nil denoting that the value isn't there.
> a = { }
> print(a[1])
nil
> a = { "abc" }
> print(a[1])
abc
> a[1] = nil -- this is just erasing 'abc' from the table; not add/insert nil
> print(a[1])
> nil
Thus they never constitute towards the size of the table.
The length operator returns, n, the count of the elements in a sequence; a sequence is a table with values (non-nil of course - which is implied since one can never insert a nil as noted above) indexed by contiguous integers starting from 1 extending to some positive integer n. If they aren't continuous (broken with holes) then the operator # shouldn't be used. The Lua manual specifically calls out that using # is defined only if a table is a sequence. However, note that non-integer keys have no bearing on the sequence nature of the table.
Now that you've clarified what your code is doing:
b.x actually winds up being a one element table for which the single element is another table due to how your code calls table.insert:
b.x = {
[1] = { <======= this single element in the top-level
["one"] = "a", b.x table is what the # operator counts
["two"] = "b", when you apply it as #b.x
["three"] = "c"
}
}
Thus, calling #b.x will always return 1 no matter what you pass to your function, because you're always adding that table as a single element in the originally empty table you initialize b.x to be.
Note however that even if you didn't create this nested table, the value returned from # still wouldn't be what you're expecting. The # operator does not count nil values. What the # operator counts is the length of the sequential numerical indices of a table starting at 1 (and is not defined for tables with non-sequential numerical indices). Thus,
#{ [1]="a", [2]="a" } evaluates to 2
#{ [1]="a", [3]="a" } is not defined by the Lua standard, because of non-sequential indices
#{ [1]="a", ["two"]="b" } evaluates to 1 (because "two" isn't a number, it's a string).
Previous answer...
Not sure where you're getting 1 from:
> a = {}
> a[1] = "a"
> a[2] = "b"
> a[3] = "c"
> a[4] = nil
> a[5] = nil
> print(#a)
3
(Note that assigning nil as a value at the end of a table does nothing - you'd get the same result omitting the a[4] and a[5] lines.)
Did you perhaps actually skip a[2]? That would result in #a being 1, since it only counts contiguous items starting from index 1.
You are constructing a table and inserting it into an empty table with key 1. If you want to insert multiple elements, you have to call insert for each one.
And, the table you are constructing has string keys, which don't influence # at all.
I suggest you use an IDE with a debugger. See that [lua] tag wiki.

Resources