# Implementation differences ## Limitations The following features are not yet supported or are partially supported in LinkML-Scala: - Arrays - Boolean expressions (`any_of`, `none_of`); initial support in SHACL - Partial support for default values (`ifabsent`) - Only enum defaults are supported, only in the Scala generator - Partial support for computed values (e.g., `equals_expression`) - Only string interpolation is supported, only in the Scala generator - Partial support for type designators (`designates_type`) - Supported in the Scala generator and in YAML/JSON serialization. Not yet in JSON Schema or SHACL. - Enum inheritance, dynamic enums (`include`, `minus`, `reachable_from`) - Rules (`rules`) - Null semantics (see below) ## Eager validation of references All LinkML references (like `slot_name` in `slots: [ slot_name ]`) are eagerly checked when creating the SchemaView. SchemaView is not able to proceed with derivation if this requirement is not satisfied. ## Emitted prefixes Metamodel `emit_prefixes` is honored, meaning the following prefixes are defined automatically in all schemas: - `linkml`: https://w3id.org/linkml/ - `rdf`: http://www.w3.org/1999/02/22-rdf-syntax-ns# - `rdfs`: http://www.w3.org/2000/01/rdf-schema# - `xsd`: http://www.w3.org/2001/XMLSchema# - `skos`: http://www.w3.org/2004/02/skos/core# - `dcterms`: http://purl.org/dc/terms/ - `OIO`: http://www.geneontology.org/formats/oboInOwl# - `owl`: http://www.w3.org/2002/07/owl# - `pav`: http://purl.org/pav/ ## Default `default_range` If a `default_range` is not provided, then it will be filled with `string` (as per [the specification](https://linkml.io/linkml-model/latest/docs/specification/04derived-schemas/#rule-populate-schema-metadata)) This is always honored in LinkML-Scala. To make generators to emit an "accept anything" schema, set the range to a class with uri `linkml:Any`, as described [here](https://linkml.io/linkml/schemas/advanced.html#linkml-any-type). ## Default `default_prefix` If a `default_prefix` is not provided, then the schema's `id` will be used instead. This ensures that all schema Elements always can construct a valid URI, even if it is synthetic. ## Always meaningful enums Enum `permissible_values` always have a meaning, even if `meaning` is not explicitly defined. Thanks to this, enum values can always be represented as IRIs in RDF, and LinkML-Scala does not allow string-based enums. ## Additional identifier constraints The identifier slot for classes must have a scalar `type` range. It is an error to have an `enum` or `class` identifier. ## Tree root extension LinkML-Scala provides a `tree_root_as` extension for classes, which allows specifying how the `tree_root` class will be laid out. For example, this allows specifying that the root of a JSON document should be a JSON array with instances of this class: ```yaml SomeClass: tree_root: true extensions: tree_root_as: list attributes: id: range: string identifier: true value: range: integer required: true ``` JSON Schema generated from this LinkML schema accepts: ```json [ { "id": "1", "value": 1 }, { "id": "2", "value": 2 }, { "id": "3", "value": 3 } ] ``` But rejects: ```json { "id": "1", "value": 1 } ``` `tree_root_as` accepts the following options: * `plain`: object instance, * `optional`: object instance or null, * `list`: array of object instances, may be empty, * `compact_dict`: dict object mapping the key field to the identifier-optional object instances * `simple_dict`: dict object mapping the key field to the value field of the object instances ## Inline type semantics Different forms: - `Plain` - In JSON the inlined class is always present. In RDF there MUST always be exactly one property representing this slot. - `Optional` - in JSON the inlined class may be present, may be omitted or may be null. In RDF there MUST be at most 1 property. - `List` - In JSON this is an array, which may be an empty array, may be omitted or may be null. No assumed constraints in RDF. - `Dict(Form)` - In JSON this is a `form` (`SimpleDict` or `CompactDict`) object, which may be omitted, may be an empty object or may be null. No assumed constraints in RDF. A slot can explicitly inline (`inlined: true`) a class, or implicitly inline a class, if the class does not have an identifier. LinkML-Scala uses the following logic when a slot `s` is inlining a class `c`: - If `s` is not multivalued: - If `s` is required, then the inline type is `Plain`, - If `s` is not required, then the inline type is `Optional`. - If `s` is multivalued: - If `s` has `inlined_as_list`, then the inline type is `List`, - Else if `c` does not have an `identifier` or `key` slot, then the inline type is `List`, - Else if `c` has 2 slots in total or 2 required slots, then the inline type is `SimpleDict`, - Otherwise, the inline type is `CompactDict`. ## Null semantics We're working on strict null semantics for LinkML instances - formalizing the usages of null, compatible with the expected metamodel structure. (Not yet fully implemented) CompactDict / SimpleDict: - `{ key: null }` (canonical) = `{ key: {} }` - Means `Map("key" -> RangeClass("key"))` - `{ key: [] }` not allowed - `` (canonical) = `{}` = `null` - Means empty collection `Map()` List: - `[ {} ]` - Means a single instance with all default values `Seq(RangeClass())` - `[ null ]` not allowed - `{}` not allowed - `` (canonical) = `null` = `[]` - Means empty collection Optional: - `{}` - Means slot is defined, with all default values `Some(RangeClass())` - `` (canonical) = `null` - Means `None` - `[]` not allowed