Discussions related to Visual Prolog
Peter Muraya
VIP Member
Posts: 147
Joined: 5 Dec 2012 7:29

Conflicting support instances

Unread post by Peter Muraya »

Hi all,
Can you help me to solve the following error:-
Conflicting support instances 'expression{@Type}{::user_defined}' and 'expression{@Type}{::range}'
It arises from compiling the code below comprising of parameterized interfaces. I intended to use the parameterized interfaces to allow the compiler to report such errors as mixing of data types. For instance, in
X:add(Y) = Z,
The compiler would report an error if X, Y and Z are not expressions of the same type, thus preventing me from mixing ranges with scalar. However, ranges and scalars all belong to a category of expressions referred to as user defined expressions. It is this fact that I am trying to implement in the following code.

Code: Select all

interface expression{@Type}      properties           type:@Type.      predicates           add:(expression{@Type})->expression{@Type}. end interface   interface user_defined supports expression{user_defined} end interface   interface range supports user_defined, expression{range} end interface   interface scalar supports user_defined, expression{scalar} end interface     implement main     open core   clauses     run() :-         succeed. end implement main   goal     console::runUtf8(main::run).
Mutall Data Management Technical Support
Martin Meyer
VIP Member
Posts: 328
Joined: 14 Nov 2002 0:01

Unread post by Martin Meyer »

Hi Peter,

I suppose the conflicting support instances error is correct behavior of the compiler.

The compiler throws it, because for example interface range (directly) supports expression{range} and (indirectly) also supports expression{user_defined}. Thus in one way it's stated, that in the interface range the values of property type have type range and the other way around it's declared, that the type of these values is instead user_defined.

The circumstance, that user_defined is a supertype of range (because range supports user_defined) does not influence the conflict. So, it's not (what one might conjecture), that the compiler chooses the more special type of the both (i.e. range) as the type of the values of property type.

The below code compiles. Does it apply to what you intend to do?

Code: Select all

interface expression{@Type}     properties         type : @Type.     predicates         add : (expression{@Type})             -> expression{@Type}. end interface   interface user_defined{@Type}     supports expression{@Type} end interface   interface range     supports user_defined{range} end interface   interface scalar     supports user_defined{scalar} end interface     implement main     open core   clauses     run() :-         succeed. end implement main   goal     console::runUtf8(main::run).
Best regards
Martin
Peter Muraya
VIP Member
Posts: 147
Joined: 5 Dec 2012 7:29

Conflicting support instances

Unread post by Peter Muraya »

Hi Martin,
Thanks for your response. Your code is very close to what I'm looking for. When I adopted it another issue cropped up: type incompatibility. At some point I need to convert a static string to a user defined expression. Here are my failed attempts, which the compiler does not like throwing the error message
The expression has type 'user_defined{@Type}{range}', which is incompatible with the type 'user_defined{@Type}{object}'


How should I declare the str_2_user_defined predicate?

Code: Select all

interface test      predicates            %str_2_user_defined:(string)->user_defined determ.            %str_2_user_defined:(string)->user_defined{_} determ.             str_2_user_defined:(string)->user_defined{object} determ. end interface   class test:test end class   implement test      clauses           str_2_user_defined("r")=range::new().           str_2_user_defined("s")=scalar::new(). end implement
Mutall Data Management Technical Support
Martin Meyer
VIP Member
Posts: 328
Joined: 14 Nov 2002 0:01

Unread post by Martin Meyer »

Despite object being a supertype of range, user_defined{object} is no supertype of user_defined{range}, and hence the compiler throws that type incompatibility error. I wonder whether this behavior of the compiler has an inherent reason or could be changed in a future VIP version.

Below variant of your code is a little less elegant, but compiles:

Code: Select all

interface expression{@Type}     domains         type = @Type. end interface   interface user_defined{@Type}     supports expression{@Type} end interface   %--   interface range     supports user_defined{range} end interface   class range : range end class   implement range end implement   %--   interface scalar     supports user_defined{scalar} end interface   class scalar : scalar end class   implement scalar end implement   %--   interface test     domains         userDefined =             scalar(scalar);             range(range).      predicates             str_2_user_defined : (string)                 -> userDefined                 determ. end interface   class test:test end class   implement test      clauses           str_2_user_defined("r") = range(range::new()).           str_2_user_defined("s") = scalar(scalar::new()). end implement
Regards
Martin
Peter Muraya
VIP Member
Posts: 147
Joined: 5 Dec 2012 7:29

Conflicting support instances

Unread post by Peter Muraya »

Martin, thanks.
I appreciate the compiler being strict with type checking because that is what lead me to using parameterized classes and interfaces in the first place, but in a case such as this I think there is enough information for the compiler to figure out that user_defined{object} is a supertype of user_defined{range}, isn't there? Thomas?.

I see you have solved this using domain usedDefined; I have tried to do away with complex domains because I have found that they are a real pain when you have to do large scale changes to the code. Objects are much less painful, so following your idea and in the spirit of objects, I will settle for the following alternative:-

Code: Select all

interface expression{@Type}      properties           type:@Type. end interface   interface user_defined{@Type} supports expression{@Type} end interface   class user_defined{@Type}:user_defined{@Type}      constructors           new:(@Type). end class   implement user_defined{@Type}       facts             type:@Type.       clauses             new(Type):-type:=Type. end implement   interface range supports user_defined{range} end interface   class range:range end class   implement range inherits user_defined{range}      clauses            new():-user_defined::new(This). end implement   interface scalar supports user_defined{scalar} end interface   class scalar:scalar end class   implement scalar inherits user_defined{scalar}        clauses             new():-user_defined::new(This). end implement     interface test      predicates            str_2_user_defined:(string)->user_defined{object} determ. end interface   class test:test end class   implement test      clauses           str_2_user_defined("r")=user_defined::new(range::new()).           str_2_user_defined("s")=user_defined::new(scalar::new()). end implement     implement main   clauses     run() :-         succeed. % place your own code here   end implement main   goal     console::runUtf8(main::run).
Mutall Data Management Technical Support
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

If we go back to the first mail and consider the range interface

Code: Select all

interface expression{@Type}      properties           type:@Type.      predicates           add:(expression{@Type})->expression{@Type}. end interface   interface user_defined supports expression{user_defined} end interface   interface range supports user_defined, expression{range} end interface
And then "expand" the supported interfaces into it:

Code: Select all

interface range supports user_defined, expression{range} % from user_defined properties     type : user_defined. predicates     add : (expression{user_defined}) -> expression{user_defined}. % from expression{range} properties     type : range. predicates     add : (expression{range}) -> expression{range}. end interface
As you can see there are two properties named type, one of type user_defined and one of type range (likewise there are two add predicates with each their type).

We have decided that such code is illegal in Visual Prolog, because we believe it cause more confusion than it would help. It is not a matter of whether we can make the compiler deal with such code or not; we don't think that programmers should deal with such code.

The mails also touches the issue of what we call structural subtyping: If A is a subtype of B is xxx{A} then also a subtype of xxx{B}.

In this case it is not: i.e. scalar is a subtype of object, but user_defined{scalar} is not a subtype of user_defined{object}.

A simple little (counter) example shows that this would not make sense:

Code: Select all

clauses     counterExample() :-         Scalar = scalar::new(),         setTypeToObject(Scalar),  % illegal user_defined{scalar} is not a subtype of user_definef{object}         Scalar:type ???.   predicates     setTypeToObject : (user_defined{object}). clauses     setTypeToObject(UserDefinedObject) :-         UserDefinedObject:type := object::new().

Scalar is a scalar object, hence its type property must have the type scalar. But if user_defined{scalar} was a subtype of user_defined{object} then it would be legal to call setTypeToObject. However setTypeToObject set the type property to something which is not a scalar.

That should cover the technicalities in the code, the remaining question is why do you want to mix range and scalar like that? I believe it would cause many problems because you will never really know whether you are dealing with an object whose type property is a scalar or a range (and neither will the compiler).
Regards Thomas Linder Puls
PDC
Martin Meyer
VIP Member
Posts: 328
Joined: 14 Nov 2002 0:01

Unread post by Martin Meyer »

Hello Thomas,

your counter example is greatly enlightening the subtyping thing, thanx!

Best regards
Martin
Peter Muraya
VIP Member
Posts: 147
Joined: 5 Dec 2012 7:29

Conflicting support instances

Unread post by Peter Muraya »

Thanks Thomas.

You clarified the subtyping question very well.

About the mixing of the scalar and range....my intention is not to really mix them as such, but to implement the fact that the range and scalar objects in my project do have some common properties defined by the user_defined interface. I omitted such properties in my example to keep the code short and focused to the problem I was encountering.
Mutall Data Management Technical Support
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

It is extremely normal to share common entities through a common base class. But it seems that you are trying to "force" non-common things into the common part. The type property contains a radically different entity in the two cases, hence it does not seem like a common property.

A more normal way to deal with the common base and the specialized classes, could be like this:

Code: Select all

interface user_defined domains     type = range; scalar.   properties     type : type (o).   predicates     isRange : () -> range Range determ.     isScalar : () - scalar Scalar determ. end interface user_defined   interface range supports user_defined end interface range   class range : range end class range   implement range clauses     type() = range.   clauses     isRange() = This.   clauses     isScalar() = _ :-         fail. end implement range
(I haven't inherited anything. I would inherit using the Support pattern).
Regards Thomas Linder Puls
PDC
Post Reply