typedb / typeql

TypeQL: the power of programming, in your database
https://typedb.com
Mozilla Public License 2.0
219 stars 46 forks source link

Role names of a relation cannot be reused in its sub-relations via override #274

Closed james-whiteside closed 1 year ago

james-whiteside commented 1 year ago

Description

If we delcare a relation and a sub-relation that share a role name via an override:

define

membership sub relation,
    abstract,
    relates parent,
    relates member;

group-membership sub membership,
    relates group as parent,
    relates member as member;

then we get an error:

[TYW34] Invalid Type Write: The role type 'member' is already declared by a supertype of 'group-membership'.

This does not make sense as, given that membership is abstract, when including a group-membership in a query pattern:

(group: $g, member: $m) isa group-membership;

the use of member can only refer to group-membership:member as a group-membershipwith a membership:member roleplayer is forbidden by the schema.

In fact, it should also be possible for non-abstract super-relations as well:

define

# not abstract
membership sub relation,
    relates parent,
    relates member;

group-membership sub membership,
    relates group as parent,
    relates member as member;

In this case, the differentiation between the super-role and sub-role is made by the context of its usage:

(group: $g, member: $m) isa group-membership;
(parent: $g, member: $m) isa membership;

where in the first case member would be interpreted as group-membership:member, and as membership:member in the second. If role (and potentially relation) types are variablised in the query, then the relation type should always provide the context for the role type.

Environment

  1. OS: MacOS 12.6.1
  2. TypeDB version: 2.16.1
  3. TypeDB client: client-java

Reproducible Steps

Steps to create the smallest reproducible scenario:

  1. Write a query that defines the schema elements above (membership and group-membership).
  2. Run the query.

Expected Output

Query runs and schema is successfully defined.

Actual Output

[TYW34] Invalid Type Write: The role type 'member' is already declared by a supertype of 'group-membership'.
james-whiteside commented 1 year ago

Related issue: https://github.com/vaticle/typeql/issues/203

james-whiteside commented 1 year ago

This issue might also be related: https://github.com/vaticle/typedb/issues/6534

brettforbes commented 1 year ago

i agree this is an important logic problem. Roles are not always a logical sub-set of a larger role, and in fact sometimes the roles are the same. This is really due to the construction of language, and TypeQL should allow this since the role is always fully qualified (ie. it is called with the relation name as well)

flyingsilverfin commented 1 year ago
define

# not abstract
membership sub relation,
    relates parent,
    relates member;

group-membership sub membership,
    relates group as parent,
    relates member as member;

This one - i agree it might be nice but how important is it to actually have group-membership:member and membership:member being different role types? This is much harder to implement than allowing abstract relations to have concrete role types inside them :)

james-whiteside commented 1 year ago

There's a big difference. If I say that I want something to play group-membership:member then I don't want it to be able to play membership:member or member in other subtypes of membership.

flyingsilverfin commented 1 year ago

Humm okay, interesting. Not sure that one will be coming yet, have to think about it more

flyingsilverfin commented 1 year ago

Note: for abstract relations/roles, we will want to be able to do something like this:

request sub relation @abstract,
  relates subject @abstract,
  relates requester,
  relates respondent;
flyingsilverfin commented 1 year ago

The final behaviour here was discussed and implemented.

1) Role types are now concrete separately from their relations' abstractness, therefore inheritable and reusable (https://github.com/vaticle/typedb/pull/6885) 2) Inherited role types are no longer allowed to be accessed via alias in the sub-relation type (https://github.com/vaticle/typedb/pull/6916) Given

define
employment sub relation, relates employee;
part-time-employment sub employment;

We now disallow

define
person plays part-time-employment:employee;

Since part-time-employment:employee is an alias for employment:employee

Previously, allowing this plays would actually implicitly allow playing other types of relations that inherited emplyoment:employee as well, such as for example non-profit-employment sub employment, even though a person maybe only should be restricted to part-time-employments in a model.

3) We disallow creating a sub-role type with the same name to avoid confusion and ambiguity in the following use case (pre-existing behaviour)

define
  multi-employment sub employment,
    relates employee-1 as employee,
    relates employee-2 as employee,
    ...
    relates employee as employee;

Here, querying match (employee: $x) isa multi-employment is ambiguous we either want to query for specifically the new 'employee' in multi-employment or all employee-* in multi-employment (via subtyping).

Another way to see this from a set semantics is that we can see multi-employment as sharing (ie being a subset) of employment - therefore we can ignore the scoping of role types when considering role names. In this model, calling a subtype employee while the parent is employee is as confusing as naming an attribute supertype name and its subtype name as well. If they have the same name, they should occupy the same 'space'.

The solution to this is create a new role type when you want to carve out a subset specific to the relation subtype.

define
  multi-employment sub employment,
    relates employee-1 as employee,
    relates employee-2 as employee,
    ...
    relates multi-employee as employee;