E07185: an abstract '$', '$$' or '#?' is only for a type with no fields (counting inherited ones): a sub-type's generated operator covers only its own fields, so these fields would be left out - give the operator a body, or use 'default operator' for it
What went wrong
An abstract '$', '$$' or '#?' is declared on a type that has fields - its own, or ones it inherits. These three operators are the ones a sub-type's 'default operator' builds from fields. Below a super whose operator has a body, the generated one calls it and adds the sub-type's own fields: 'Circle(Shape(name=circle), radius=5.0)'. Below an ABSTRACT one there is nothing to call, so the generated operator covers only the sub-type's own fields - and the super's fields would silently be left out: 'Circle(radius=5.0)', with Shape's 'name' gone.
So an abstract '$', '$$' or '#?' is only for a type with nothing to lose: a field-less root of a hierarchy, or a trait. Where the data is, the operator has a body. The error is reported at the abstract operator, on the type that has (or inherits) the fields.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1180 (Define an abstract Shape class with an area method, and a concrete Circle subclass.)
The [EXAMPLE] section below shows an abstract Shape with a 'name' field and an abstract '$', then the fix - the '$' generated on the type that has the field, so a Circle's generated '$' folds 'name' in - and a field-less root that may keep its '$' abstract (good_root.ek9).
How to fix it
- Replace the abstract operator with 'default operator $' (or '$$', '#?').
- Or give it a hand-written body - for example when the fields are not to be exposed in '$' or '$$'.
- Or, if the type is meant to be a pure polymorphic root, move the fields down to the sub-types.
Common causes
- Marking '$' abstract on an abstract base class "so every sub-type must say how it prints", while the base itself holds data
- A field added later to a root that was field-less when '$' was made abstract
- An abstract middle type, with no fields of its own, that inherits fields from its super
See also
- E07185: an abstract '$', '$$' or '#?' on a type with fields (this error)
- E07190: 'default operator' on a type whose super does not declare the operator at all
- E07183: '==' and '<=>' (sameness) cannot be abstract at all
- E07184: '#?' goes with the type's sameness
- E07237: a concrete record needs a field
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E07185: an abstract '$', '$$' or '#?' is only for a type with no fields (counting inherited ones): a sub-type's generated operator covers only its own fields, so these fields would be left out - give the operator a body, or use 'default operator' for it
#!ek9 defines module error.e07185.bad defines class Shape as abstract name as String: String() //A sub-type's generated '$' would cover only its own fields, never name default operator ? operator $ as pure abstract <- rtn as String?
Fixed: Use 'default operator $' (or give it a body)
#!ek9 defines module error.e07185.good defines class Shape as abstract name as String: String() //Generated over name; a sub-type that adds fields declares its own default operator ? default operator $
Fixed: A field-less root may keep its '$' abstract: it has nothing to lose
#!ek9 defines module error.e07185.good.root defines class Measurement as abstract operator $ as pure abstract <- rtn as String? default operator ? Length extends Measurement metres as Float: 3.0 override operator $ as pure <- rtn as String: `${metres}m` default operator ?
Questions and answers
These Q&A entries show E07185 and its fix: