Eiffel: Invalid constraint for formal generic paramete - generic-programming

Following with strange patterns for some, can't I do that? The compiler says Invalid constraint for formal generic parameter
class PARENT[G -> CHILD[like Current]]
feature -- Access
children: LIST[G]
end
class CHILD[H -> PARENT[like Current]]
feature -- Access
father: H
end
to be able to do something like
class WIDOW_PARENT
inherit
PARENT[BLACK_CHILD]
end
class BLACK_CHILD
inherit
CHILD[WIDOW_PARENT]
end
If I don't do it with genericity, I'd have to redefine the children collection from
children: LIST[CHILD] to children: LIST[BLACK_CHILD] into the WIDOW_PARENT class
father: PARENT to father: WIDOW_PARENT into the BLACK_CHILD class
instead of only specify it in the inherit clause... Hope it makes sense
Update
As I solved it with Alexanders answer, I'm stuck further doing a conformity check. I'm trying to set an HTTP router depending on entities and if its a child entity it should be able to do a http://host:port/entity/child_entity/id to get all child entities from entity. For that I'd like to add to the generic router a check. On something like ANY_PARENT_DB_ENTITY such as
if ({G}).conforms_to ({CHILD_DB_ENTITY[ANY_PARENT_DB_ENTITY]}) then
friend.act_like_a_father
else
friend.act_like_a_mate
end

In contemporary Eiffel, anchored types cannot be used in formal generic constraints, thus the error. It's still possible to have mutual constraints by repeating class types explicitly:
class PARENT [G -> CHILD [PARENT [G]]]
class CHILD [H -> PARENT [CHILD [H]]]
With this change, the example compiles.

Being still the best solution for me, the only solution to my whole pattern is to redefine in my router class the set_handler method with
CHILD_DB_ENTITY
deferred class
CHILD_DB_ENTITY[H -> PARENT_DB_ENTITY[CHILD_DB_ENTITY[H]]]
inherit
DB_ENTITY
feature
parent: H
ENTITY_HANDLER
ENTITY_HANDLER[G -> DB_ENTITY, H -> DB_SERVICE[G] create make end]
feature
item_prototype: detachable G
set_handler
do
setting_url_("http://host:port/" + {like item_prototype}.out)
...
end
end -- Class
CHILD_ENTITY_HANDLER
CHILD_ENTITY_HANDLER[G -> CHILD_DB_ENTITY[PARENT_DB_ENTITY[G]], H -> DB_SERVICE[G]]
inherit
ENTITY_HANDLDER
redefine
set_handler
end
feature
set_handler
do
Precursor
setting_url_("http://host:port/" + ({like item_prototype}).out + "/" + ({like item_prototype.parent}).out + "/{id}")
end
end -- Class
PARENT_ENTITY_HANDLER
PARENT_ENTITY_HANDLER[G -> PARENT_DB_ENTITY[CHILD_DB_ENTITY[G]], H -> DB_SERVICE[G]]
inherit
ENTITY_HANDLDER
redefine
set_handler
end
feature
set_handler
do
Precursor
setting_url_("http://host:port/" + ({like item_prototype}).out + "/" + ({like item_prototype.children.item}).out + "/{id}")
-- children being a LINKED_LIST[PARENT_DB_ENTITY]
end
end -- Class
I hoped there was a way to get it with polymorphism in same class, but it also makes sense to have to redefine it that way...

Related

Error code: VUTA(3) Error: separate target of the Object_call is not controlled

I'm a complete beginner to Eiffel and I'm implementing a linked list as an exercise. I get the following error in the feature has (which tells you if the list contains v).
Error code: VUTA(3)
Error: separate target of the Object_call is not controlled.
What to do: ensure the target of the call is controlled or is not separate.
Class: MY_LINKED_LIST [G]
Feature: has
Type: Generic #1
Line: 159
then
-> if l_cursor_a.item.is_equal (v) then
Result := True
The weird thing is that when I change the '.is_equal' for a '=' the error is gone. I don't know what 'controlled' in the error description means and what difference to it does make to use '=' in this context. The code is the following:
MY_LINKED_LIST[G]
class
MY_LINKED_LIST[G]
feature -- Access
item: G
require
not off
do
check
off: attached cursor as l_cursor
then
Result := l_cursor.item
end
end
first,
last: detachable like item
feature -- Measurement
count: INTEGER
feature -- Element change
feature -- Status report
index: INTEGER
before: BOOLEAN
after: BOOLEAN
has (v: like item): BOOLEAN
require
local
l_cursor: like cursor
do
from
l_cursor := first_element
until
not attached l_cursor or Result
loop
check
attached l_cursor as l_cursor_a
then
if l_cursor_a.item.is_equal (v) then
Result := True
end
l_cursor := l_cursor_a.next
end
end
ensure
function_not_change_state: item = old item
end
feature {NONE} -- Implementation
cursor,
first_element,
last_element: detachable MY_CELL[G]
end -- class
MY_CELL[G]
class
MY_CELL[G]
feature -- Access
item: G
The error message is related to SCOOP — the model of concurrent programming built into Eiffel. According to it, a feature can be called on a separate object only when the object is controlled. This is achieved when the target of the call is an argument of a feature, or when a special separate instruction is used. In your case, the latter would look like
separate l_cursor_a.item as x do
if x.is_equal (v) then
Result := True
end
end
Why l_cursor_a.item is considered separate in the first place? It has a type G, and the formal generic is unconstrained that is identical to have a constraint detachable separate ANY (so, most probably, the code above would not compile, you would need to make sure x is attached before calling is_equal on it).
The equality operator = does not perform any calls (unless the involved types are expanded, but expanded types are never separate). For reference types (including separate ones), it simply tests whether two references are the same. This explains why the error disappears when is_equal is replaced with =.
An alternative solution to avoid the error message is to change the constraint of the formal generic to be non-separate: MY_LINKED_LIST [G -> detachable ANY].
Side note. The check instruction check attached l_cursor as l_cursor_a then ... seems to be redundant, the compiler should be able to figure out automatically that l_cursor is attached.

Implementation contraint: The class feature only_from_type uses an inline agent

Is there a semantic behind not being able to have an agent into a ensure class routine or is it a current compiler restriction?
only_from_type (some_items: CHAIN[like Current]; a_type: detachable like {ENUMERATE}.measuring_point_type_generation): LINKED_LIST[like Current]
-- extends Result with given some_items which are equal to given type
do
create Result.make
across
some_items is l_item
loop
check
attached_type: attached l_item.type as l_type
then
if attached a_type as l_a_type and then l_type.is_equal (l_a_type) then
Result.extend (l_item)
end
end
end
ensure
some_items.for_all (
agent (an_item: like Current; a_type_2: detachable like {ENUMERATE}.measuring_point_type_generation) do
if attached a_type_2 as l_type_2_a and then
attached an_item.type as l_item_type and then
l_item_type.is_equal (l_type_2_a)
then
Result := True
end
end (a_type)
)
instance_free: Class
end
gives following error
And I think there is a typo here, shouldn't it be Implementation constraint instead of contraint?
Error code: VUCR
Implementation contraint: The class feature only_from_type uses an inline agent.
What to do: Remove the inline agent from the code or make the feature a non-class one.
Class: MEASURING_POINT
Feature: only_from_type
Line: 183
some_items.for_all (
-> agent (an_item: like Current; a_type_2: detachable like {ENUMERATE}.measuring_point_type_generation) do
if attached a_type_2 as l_type_2_a and then
An inline agent (like a regular feature) takes an implicit argument - current object. In a class feature (where it is used in the example), there is no current object. Therefore, an inline agent cannot be called from a class feature.
On the other hand, it might be possible to check that the agent does not use Current, and, therefore, is safe to use in the class feature. The compiler reporting the error does not implement such a functionality, and reports an implementation constraint error instead.

Eiffel: Is there a way to test a given Generic parameter of a Class without any attached instance of it?

Is there a way to test a given Generic parameter of a Class without any attached instance of it?
class BAG[G -> MOUSE]
feature --
discriminate
do
if G.conforms_to (MAMMAL) then
io.putstring ("you gave me a real animal")
elseif G.conforms_to (COMPUTER_ACCESSORY) then
io.putstring ("Seems you don't like animals such as computers")
else
io.pustring ("Still dont know what you are dealing with")
end
end
You've almost nailed it. The missing part is curly braces and parentheses:
if ({G}).conforms_to ({MAMMAL}) then
io.put_string ("You gave me a real animal.")
elseif ({G}).conforms_to ({COMPUTER_ACCESSORY}) then
io.put_string ("Seems you don't like animals such as computers.")
else
io.put_string ("Still don't know what you are dealing with.")
end
Explanation:
{FOO}, where FOO is a type name, stands for a type object. It works for any type, including formal generics, thus {G} and {MAMMAL}.
The syntax {FOO}.bar is reserved for non-object calls. But here we want an object call on the type object. Therefore, {G} is enclosed in parentheses: ({G}).conforms_to (instead of {G}.conforms_to).

Modelling with ndb

I'm quite new to ndb. This is how my structure looks like in general:
a = [b, c]
b = [d, e, f]
d = [g, h]
e = [k, l, m, n]
f = [o]
c = [p, r, t]
I have the following model.
class Child(ndb.Model):
name = ndb.StringProperty()
child = ndb.KeyProperty(kind="Child", repeated=True)
class Root(ndb.Model):
name = ndb.StringProperty()
child = db.StructuredProperty(Child, repeated=True)
I can't do this since ndb won't allow me to repeat it because I already repeat Child.
What would be the proper way to model this structure?
Since the entities of the Root and Child kinds are almost the same, The data I see you are trying to model is a classic example of one-to-many relationship between entities of the same kind. The modelling for this sort of relationship is below:
class RelatedKind(ndb.Model):
name = ndb.StringProperty()
root = ndb.KeyProperty(kind="RelatedKind")
To create entities:
a = RelatedKind(name='a')
a_key = a.put()
b = RelatedKind(name='b', root=a_key)
b_key = b.put()
c = RelatedKind(name='c', root=a_key)
c_key = c.put()
# To get all 'child' of a;
child_a = RelatedKind.query(root == a_key).fetch()
print(child_a)
# >>> [b_key, c_key]
With datastore query, and just keyproperty, you achieve the same modelling without using repeated.
If you just want to be able to store many 'Child' entities on a single 'Root', you can use a LocalStructuredProperty to contain the Child model instead (but this means it won't be indexed). There's a hint to this behavior in the App Engine NDB docs when it discusses nested structured properties:
Although a StructuredProperty can be repeated and a StructuredProperty can contain another StructuredProperty, beware: if one structured property contains another, only one of them can be repeated. A work-around is to use LocalStructuredProperty, which does not have this constraint (but does not allow queries on its property values).
Another option for modeling nested relationships like this would be to use ancestors on the keys. So, for example, let's say your Root key path were: ('Root', 1). You could add children below it with keys ('Root', 1, 'Child', 1), ('Root', 1, 'Child', 5), and so on, appending 'Child' to the keypath each time. Then, we you wanted to query for the children of an object, you could just use an ancestor query, e.g.:
def create_child(parent, name):
new_child = Child(parent=parent.key, name=name)
new_child.put()
return new_child
def get_children(parent):
return Child.query(ancestor=parent.key)
class Child(ndb.Model):
name = ndb.StringProperty()
class Root(ndb.Model):
name = ndb.StringProperty()
You don't really even need to have a Root anymore at this point, because you can assign any arbitrary keypath, and you could also use the name as an ID instead and store less information.
That said, it's really completely dependent on what you're actually trying to model, there's not really enough information here to understand what you mean.
I don't see why you need a KeyProperty on the child. You could model your relationship like so:
class Child(ndb.Model):
name = ndb.StringProperty()
class Root(ndb.Model):
name = ndb.StringProperty()
child = ndb.KeyProperty(repeated=True)
c1 = Child(name="b").put()
c2 = Child(name="c").put()
a = Root(child=[c1,c2]).put() # put returns the key; otherwise you would need c1.key() here
children_keys = a.get().child # [Key(Child, 1234), Key(Child, 4567)]
# to retrieve the children, you could do
children = [ key.get() for key in children_keys ]
Keep in mind a few things. Suppose that you imagine records as being like files on your filesystem.
A KeyProperty is a pointer to another file.
A repeated property just stores multiple values.
There's no reason to use a structured property at all in this example, so let's skip that.
So, if you have the "root" object "contain" all the children via a repeated property, that'll result in you having a root file that can only be updated once every second or so, and it'll eventually grow too large.
So, in lieu of that, you have a few choices. You can use use ancestor queries, like Jeff mentioned. Or, you can just use all pointers and use a query to child any node's children:
class Node(ndb.Model):
parent = ndb.KeyProperty(kind='Node')
def get_children(self):
return Node.query().filter(Node.parent == self.key)
You can use get_children to fetch any node's children. Note that this part is eventually consistent, so recently added nodes won't necessarily show up in get_children for generally only a second or so.
root = Node(parent=None)
child1 = Node(parent=root)
child2 = Node(parent=root)
child3 = Node(parent=root)
sub_child1 = Node(parent=child1)

db.Key.from_path() does not return correct key

I am using db.Key.from_path(Model, key_name) in several different places in my code and then call either db.get() or Model.get_by_key_name(). I noticed that these latter commands were always returning 0 items even though I knew for sure I should be getting something back. Upon closer inspection, I noticed that the db.Key.from_path() command was not returning the correct key. The key returned looks very similar, especially at the beginning, but some of the characters are different and it is about 75% shorter than the key shown in the datastore viewer. Has anyone else encountered this? Thanks.
Here is some sample code:
class Root(db.Model):
pass
class Parent(db.Model):
pass
class MyModel(db.Model):
pass
root = Root().put()
parent = Parent(key_name=parentname,parent=root).put()
mymodel = MyModel(key_name=mymodelname,parent=parent).put()
mymodel_k = db.Key.from_path('Parent','parentname','MyModel','mymodelname')
mymodel = db.get(mymodel_k)
mymodel is None
you are not constructing the path correctly with all the ancestors.
root = Root().put()
parent = Parent(key_name=parentname, parent=root).put()
mymodel = MyModel(key_name=mymodelname, parent=parent).put()
Root -> has no parents
Parent -> has parent Root
MyModel -> has parent Parent
db.Key.from_path('Parent','parentname','MyModel','mymodelname')
this one misses the Root ancestor which is contained in the Parent Key.
the right key would be:
db.Key.from_path('MyModel', 'mymodelname', parent=parent)
and this is why they key you create is shorter! one ancestor is missing.
It looks like there are two ancestor levels, so you should use this:
Key.from_path('Root', root.key().id(), 'Parent','parentname','MyModel','mymodelname')
or
Key.from_path('Parent','parentname','MyModel','mymodelname', parent=root)

Resources