After reading about support for algebraic datatypes in QL, I'm trying to define a List
type in the lgtm console:
newtype TList =
TNil()
or
TCons(int x,TList xs)
This seems to work. But then I try to define auxiliary classes in order to have a toString()
predicate:
class List extends TList {
abstract string toString();
}
class Nil extends List,TNil {
override string toString() {
result = "Nil"
}
}
class Cons extends List,TCons {
override string toString() {
// what to put here?
// I would like something like result = x.toString() + ':' + xs.toString()
}
}
And here I'm stumped. I don't know how to refer to the constructor parameters x
and xs
from within Cons
. I tried this.x
and this.xs
, but it doesn't seem to work.
How can I refer to constructor parameters inside a member predicate?
Since Cons
extends TCons
, you can treat this
as an instance of TCons
anywhere within a member predicate of Cons
. This means that you can compare this
to a particular instance of TCons
, and bind variables to the constructor parameters.
override string toString() {
exists(int x, List xs |
this = TCons(x, xs) and
result = x.toString() + ":" + xs.toString()
)
}
Since you'll likely want to use the constructor parameters in other member predicates of Cons
as well, you could instead declare fields to capture the constructor parameters once in the characteristic predicate, and then use them in member predicates:
class Cons extends List, TCons {
int x;
List xs;
Cons() {
this = TCons(x, xs)
}
override string toString() {
result = x.toString() + ":" + xs.toString()
}
}
Just a reminder: As the QL handbook page you link to indicates, the syntax for algebraic datatypes in QL is still experimental and subject to change.