Shorthand
DataCanon Shorthand — Version 1 Draft
Status: Draft for independent implementation review
Depends on: DataCanon Core Version 1
Scope: Strict Shorthand parsing and identity-preserving rendering
Out of scope: Optional Shorthand preprocessing, YAML interchange, HDF5, and persistence conventions
Introduction
DataCanon Shorthand is a human-readable textual representation of DataCanon Instances (DCIs). It provides notation for all 24 DataCanon Types (DCTs) defined by DataCanon Core Version 1.
Shorthand does not define DCI identity. The core specification defines DCTs, equality, canonical binary encoding, and fingerprinting. A Shorthand document represents exactly one DCI; its whitespace and textual layout do not participate in that DCI’s identity.
A conforming Shorthand parser MUST recover the DCI specified by a valid Shorthand document. A conforming Shorthand renderer MUST produce valid Shorthand that a conforming parser recovers as a DCI equal to the original.
Shorthand is not a canonical textual encoding. Multiple texts may represent the same DCI, and no particular rendering layout is required.
Conformance and terminology
The terms MUST, MUST NOT, SHOULD, and MAY indicate requirements and recommendations for implementations of this specification.
The definitions, invariants, and equality relations of DataCanon Core Version 1 take precedence over any convenience afforded by Shorthand syntax. A syntactically well-formed expression that violates a DCT invariant is invalid Shorthand.
A conforming strict parser MUST:
- parse exactly one complete DCI and reject unexpected trailing input;
- interpret the constructs specified here according to their defined DCTs;
- preserve constituent identity, including unreduced Fractions and floating-point signed zero;
- reject invalid DCT constituents and malformed syntax; and
- operate without performing substitutions, mathematical evaluation, or application-specific transformations.
A conforming renderer MUST preserve DCI equality across a strict render–parse round trip. It MAY choose whitespace, indentation, line breaks, and other identity-preserving layout conventions.
The separately specified Shorthand preprocessor MAY be applied before strict parsing. It is not part of the strict grammar.
Lexical rules
Input and whitespace
Shorthand is Unicode text. Strings may contain Unicode scalar values as defined by DataCanon Core Version 1.
Outside quoted strings, the recognized whitespace characters are the ASCII space (U+0020), horizontal tab (U+0009), carriage return (U+000D), and line feed (U+000A). Whitespace may appear between syntactic tokens except where this specification explicitly requires adjacent characters.
Strict Shorthand does not define comments. An empty or whitespace-only document is invalid.
Digits and identifiers
A digit is one of the ASCII characters 0 through 9.
An identifier begins with an ASCII letter (A–Z, a–z) or underscore (_), followed by zero or more ASCII letters, digits, or underscores.
The strict grammar recognizes only the identifiers explicitly assigned meaning below. Arbitrary identifiers are not variables and MUST be rejected in strict parsing.
Identifiers and keywords are case-sensitive. In particular, true, false, and null are lowercase.
Strings
A String literal is delimited by double quotation marks ("). Its contents are a sequence of Unicode scalar values, optionally using the following escapes:
| Source characters | Decoded character |
|---|---|
\" | quotation mark |
\\ | backslash |
\n | line feed |
\r | carriage return |
\t | horizontal tab |
No other backslash escapes are defined. A backslash followed by any other character MUST be rejected. Literal Unicode characters, including literal line breaks, may appear inside a quoted string, provided the decoded result is a valid DataCanon String. No Unicode normalization occurs.
A renderer MUST escape quotation marks and backslashes so that they cannot terminate or alter a String literal; it MAY escape the three supported control characters above.
Block Strings
In addition to ordinary quoted Strings, Shorthand supports literal and folded block Strings. Both forms represent the String DCT and do not introduce new DataCanon Types.
A literal block begins with """ followed immediately by LF:
"""
first line
second line
"""
This represents the String first line\nsecond line.
A folded block begins with """> followed immediately by LF:
""">
This is a long String
written across several
physical lines.
"""
This represents This is a long String written across several physical lines.
Structural indentation. The opening delimiter MUST be the first non-space content on its physical line. Its indentation consists exclusively of spaces and defines the block’s structural indentation. The closing """ MUST begin at exactly the same indentation. It MAY be followed by surrounding Shorthand syntax, such as a comma, colon, or closing collection delimiter.
Each nonempty content line MUST contain at least the structural indentation. Exactly that indentation is removed. Completely empty physical lines are permitted without indentation. Any additional indentation is content.
Literal blocks. After structural indentation is removed, all content characters are preserved, including leading and trailing whitespace and physical LF characters between content lines. The newline immediately following the opening delimiter and the newline immediately preceding the closing delimiter are structural and are not included in the String.
Folded blocks. After structural indentation is removed, whitespace-only lines are discarded, trailing whitespace is removed from nonblank content lines, and the remaining lines are joined with exactly one U+0020 SPACE. Additional leading whitespace on nonblank lines is preserved. Consecutive blank lines do not introduce additional spaces or newlines.
Neither block form interprets escape sequences. Backslashes are literal characters. Strings that cannot be represented using block syntax can always be expressed using ordinary quoted Strings.
Block formatting does not participate in DCI equality, canonical byte encoding, or fingerprinting. Different textual representations that produce the same String DCI have identical canonical identity.
Numerical literals
An integer literal consists of an optional leading - followed immediately by one or more ASCII digits. It denotes an arbitrary-precision mathematical integer in decimal notation. A leading + is not supported.
A floating-point literal consists of an optional leading -, a nonempty sequence of ASCII digits, and at least one of:
- a decimal point followed by one or more ASCII digits; or
- an exponent introduced by
eorE, followed by an optional+or-and one or more ASCII digits.
A floating-point literal may have both a decimal part and an exponent, such as 1.25e-3. The scalar syntax does not require support for a trailing decimal point without following digits (for example, 1.). Array element syntax has a separate allowance for that form.
A floating-point literal denotes the finite IEEE-754 binary64 value obtained by correctly rounding its decimal value. The parser MUST reject values that cannot produce a valid finite Float DCI. Positive and negative zero are distinct.
A Fraction literal consists of an integer literal, /, and one or more ASCII digits denoting a positive denominator, with no intervening whitespace. The numerator and denominator are preserved exactly; no reduction occurs.
Examples:
| Text | DCT | Interpretation |
|---|---|---|
42 | Integer | integer 42 |
-0 | Integer | integer 0 |
-0.0 | Float | negative binary64 zero |
1e3 | Float | binary64 1000.0 |
2/4 | Fraction | numerator 2, denominator 4 |
Strict Shorthand constructs
Primitive DCTs
| DCT | Syntax | Example |
|---|---|---|
| Null | null | null |
| Boolean | true or false | true |
| Integer | integer literal | -42 |
| Float | floating-point literal | 3.5 |
| String | quoted String literal | "hello" |
Named mathematical constants
Pi denotes Constant pi; E denotes Constant e. Both tokens are
case-sensitive and are accepted wherever a Numerical DCI is permitted.
They are constant tokens, not function calls or variables.
The explicit constructor is constant("pi") or constant("e"), with exactly
one quoted String argument. The String supplies the Constant’s direct name
information; it does not become a constituent DCI. Unknown names and bare
name arguments such as constant(pi) MUST be rejected.
The default renderer emits Pi or E; longhand emits constant("pi") or
constant("e"). Numerical exponent syntax such as E**2 constructs a Power
DCI, not another spelling of Constant e. Quoted "Pi" remains a String.
Array element syntax does not accept constants or structured numerical DCIs.
Bytes
A Bytes DCI is written using one quoted hexadecimal String:
bytes("")
bytes("00ff80")
The decoded String MUST contain an even number of ASCII hexadecimal digits
(0–9, a–f, or A–F). Each pair denotes one byte in sequence order.
An empty String denotes an empty byte sequence. Separators, whitespace within
the decoded String, 0x prefixes, and non-ASCII digits are invalid.
Exactly one String argument is required. Whitespace between syntactic tokens and an optional trailing comma are permitted. A renderer emits lowercase hexadecimal digits. The text describes the exact opaque byte sequence; it does not perform character decoding or interpret a file format.
Fraction
A Fraction is written as a Fraction literal, for example 1/3 or 2/4, or
using the explicit constructor fraction(numerator, denominator).
Both constructor arguments MUST be integer literals; the denominator MUST be
positive. Exactly two arguments are required, and an optional trailing comma
is permitted. Constituents are preserved without reduction. Fraction is
distinct from Integer and Float even when their mathematical values agree.
Sum and Product
sum()
sum(1, 2, 3)
product()
product(1/2, sqrt(3))
Sum arguments are Numerical DCIs; Product arguments are Scalar Numerical DCIs. Empty and singleton instances are valid, repeated operands are retained, and an optional trailing comma is permitted. Operand order is not semantic; multiplicity and nesting are semantic.
Bounded infix forms construct the same flat nodes:
1 + 2 + 3 -> sum(1, 2, 3)
1/2 * sqrt(3) -> product(1/2, sqrt(3))
1 + 2 * 3 -> sum(1, product(2, 3))
Multiplication binds more tightly than addition. Explicit constructor operands
are not flattened: sum(1, 2) + 3 represents sum(sum(1, 2), 3).
The numerical forms construct structure; they perform no arithmetic.
Binary subtraction and general infix division are not supported. Negative
numeric literals remain available, for example 1 + -2. Parentheses retain
Tuple syntax; grouping is expressed through constructors, not grouping
parentheses. Thus (1 + 2) is a singleton Tuple containing a Sum.
OrderedProduct and array expressions
ordered_product(item, ...) constructs an OrderedProduct DCI, preserving
operand order and nesting. Zero or more Numerical DCI operands are accepted;
an optional trailing comma is permitted. No rank, shape, or mathematical
compatibility checks are performed during parsing.
The infix + always constructs Sum and accepts all Numerical DCIs. Infix *
constructs Product when every factor is a Scalar Numerical DCI; otherwise it
constructs OrderedProduct. Operand classification is structural, not numerical
evaluation. Existing precedence is unchanged: ** binds before *, which
binds before +. Complex DCIs and collection DCIs other than Array remain
invalid numerical operands.
2 * array([[1, 0], [0, 1]])
2 * array([[0, 1], [1, 0]]) + 3 * array([[1, 0], [0, -1]])
ordered_product(2, 3)
Explicit product(...) remains scalar-only. Scalar-only OrderedProducts MUST
render using ordered_product(...), because their infix form would construct
a different DCT. Renderers MUST also retain explicit constructors wherever
needed to preserve nested Sum, Product, and OrderedProduct boundaries.
Longhand always uses ordered_product(...); ordinary Shorthand may use *
when reparsing preserves the exact DCI. ordered_product is a collection
layout name accepted by per-type layout configuration.
Power
power(base, numerator)
power(base, numerator, denominator)
The base is a Scalar Numerical DCI; numerator and denominator are positive mathematical integers written as integer literals. The omitted denominator defaults to one. Optional trailing commas are permitted. Exponent constituents are not reduced.
A bounded infix form accepts a positive Integer literal without parentheses, or a positive Integer/Fraction literal inside exponent-specific parentheses:
5**2
5**(2)
5**(1/2)
An infix power MUST NOT have a Fraction base. Expressions such as
1/2**3 and 1/2**(1/3) are invalid because they resemble arithmetic division
with a different precedence convention. Use the explicit constructor instead:
power(1/2, 3)
power(1/2, 1, 3)
This restriction applies only to the infix spelling. Fraction remains a valid Power base, and Fraction literals remain permitted in parenthesized exponents.
Power binds more tightly than multiplication and addition. The two stars MUST be adjacent. Whitespace around the operator and inside exponent parentheses is permitted. Exponent parentheses are part of this construct and do not introduce general expression grouping.
Unparenthesized rational exponents, Float exponents, and chains such as
5**2**3 are invalid. Nested powers use explicit power(...) constructors.
sqrt(base) is a convenience spelling for power(base, 1, 2) and constructs
a Power DCI without evaluation. The denominator always participates in the
resulting DCI, whether or not it was written explicitly.
Quotient
quotient(numerator, denominator)
quotient(2, sqrt(3) + sqrt(2))
Both arguments are Scalar Numerical DCIs. Exactly two arguments are required; an optional trailing comma is permitted. The parser performs no division, cancellation, or denominator rationalization. Fraction literal syntax remains unchanged and constructs Fraction, not Quotient.
Complex
A Complex is written:
complex(real, imaginary)
Each component MUST parse to a Scalar Numerical DCI. The two components retain their DCTs and their individual identities.
Example:
complex(1/2, 1/2 * sqrt(3))
This notation is distinct from the special complex-number syntax used inside Arrays.
List and Tuple
A List uses square brackets or list(...); a Tuple uses parentheses or
tuple(...). Constructor arguments are the items themselves, rather than a
single collection to convert. Elements are arbitrary DCIs separated by commas.
Both forms may be empty and may have an optional trailing comma.
[]
[1, "x", 2/4]
(1, 2)
(1)
()
A single-element Tuple is (1); no trailing comma is required. List and Tuple remain distinct DCTs regardless of their contents.
Set and Mapping
Curly braces denote a nonempty Set or a Mapping, distinguished by the presence of : following the first parsed value.
{1, 2, 3}
{"a": 1, "b": 2}
{}
{} is the empty Mapping. The empty Set is written set().
The identifier emptyset is not part of strict Shorthand.
A Set may also be written set(item, ...), including set() and singleton
Sets. Constructor arguments are individual members. An optional trailing
comma is permitted in the constructor form.
A Mapping may also be written mapping(key: value, ...), including
mapping(). The constructor follows the same entry order, key uniqueness,
and optional trailing-comma rules as the brace form.
Set members are arbitrary DCIs separated by commas. They MUST be pairwise distinct under DCI equality. Set member order is not semantic. The brace form does not admit a trailing comma; the set(...) constructor does.
A Mapping consists of comma-separated key: value entries. Keys and values are arbitrary DCIs, and keys MUST be pairwise distinct under DCI equality. Entry order is semantic. A Mapping may have an optional trailing comma.
Multiset
A Multiset is written as comma-separated DCI members enclosed in
multiset(...):
multiset()
multiset(1, 1, 2)
multiset("Sr", [1, 2], [1, 2])
multiset(multiset(1, 1), 2)
Members may belong to any DCT. Repeated members are permitted and MUST be
retained. Member order is not semantic; multiplicity and nesting are semantic.
For example, multiset(1, 1, 2) and multiset(2, 1, 1) represent equal DCIs,
while multiset(1, 2, 2) represents a different DCI.
An optional trailing comma is permitted. multiset() is the empty Multiset.
A Multiset is distinct from a Set, List, or Tuple with otherwise equal members.
A renderer MAY choose any member order. It MUST preserve every occurrence and MUST NOT flatten nested Multisets. Canonical byte sorting imposes no textual member-order requirement.
UnorderedMapping
An UnorderedMapping is written:
umapping("b": 2, "a": 1)
umapping()
It follows Mapping entry syntax and uniqueness requirements, but entry order is not semantic. An optional trailing comma is permitted.
Record
A Record is written with a quoted name followed by zero or more quoted field names and DCI values:
record("Point", "x": 1.0, "y": 2.0)
record("Empty")
The Record name and each field name are DataCanon Strings. Field names MUST be distinct. Field order and the Record name participate in DCI identity. A trailing comma after the Record name or final field is permitted.
Record names and field names need not be valid Shorthand identifiers because they are quoted Strings.
Arrays
Array construct
An Array is written:
array(DATA)
array(DATA, dtype="TYPE")
array(DATA, shape=(DIMENSIONS))
array(DATA, dtype="TYPE", shape=(DIMENSIONS))
The dtype and shape options may occur in either order, at most once each. An optional comma before the closing ) is permitted.
DATA is either a single Array scalar (rank zero) or a nested bracketed collection of Array scalar elements. Array elements are not DCIs. A nested Array body is not a DataCanon List.
Examples:
array(1.0)
array([1, 2, 3])
array([[1.0, 2.0], [3.0, 4.0]])
array([1.0, -0.0], dtype="float32")
array([], dtype="float64", shape=(0, 3))
The bracketed numerical body uses comma-separated entries and rectangular nesting. The current strict parser does not permit a trailing comma inside a bracketed Array body.
Array scalar syntax
Array scalar elements may be true, false, real numeric literals, or complex numeric literals of the form:
REAL+MAGNITUDEj
REAL-MAGNITUDEj
REAL and MAGNITUDE use Array numeric syntax. The real part may be negative; the imaginary magnitude is unsigned. No whitespace is permitted within the complex literal. Exponents are permitted in either component, and the decimal point in an Array numeric literal may have no following digit (1.).
Examples:
array([true, false])
array([1., 2.5])
array([1.0+2.0j, 3.0-4.0j])
array([1e-3+2e4j, -3e2-4e-1j])
1.0+2.0j is not a valid top-level Complex DCI expression.
Portable Array types
The resulting Array MUST have one of the 14 portable Array types defined by DataCanon Core Version 1:
bool, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float16, float32, float64, complex64, and complex128.
A dtype option is a quoted type name. The portable type names above are the interoperable spelling; the Python reference parser also accepts dtype aliases recognized by NumPy when they produce a portable type. Whether to standardize aliases beyond the portable names is open for Version 1 finalization.
Inference and explicit conversion
When dtype is omitted, the reference behavior is NumPy’s array construction from the parsed Array scalar values. When shape is omitted, the reference behavior is the shape inferred from that construction.
When dtype is present, the reference behavior is NumPy Array construction with that dtype. NumPy’s conversion behavior, including any permitted rounding or lossy conversion, is intentionally retained. Shorthand does not impose a separate losslessness rule on explicit dtype conversion. The final Array MUST nevertheless satisfy the portable Array DCT’s invariants, including finiteness of floating-point and complex elements.
When shape is present, the constructed Array is reshaped using NumPy-compatible reshape semantics; the requested shape MUST be valid, have nonnegative dimensions, and preserve the element count.
Reference-version item pending: Before this draft becomes a final cross-language conformance standard, the NumPy reference version MUST be fixed. Julia and other implementations need only reproduce the resulting DCI, not use NumPy internally. The detailed inference and conversion algorithm is deliberately not reproduced in this draft.
Array identity and rendering
Array type, shape, and the exact portable element values participate in identity. Renderers MUST include dtype and shape annotations whenever omitting them would cause a conforming parser to infer a different DCI.
A renderer MUST preserve the bit identities of floating-point Array elements, including positive and negative zero, and the corresponding components of complex Array elements.
The canonical element byte stream and canonical Array encoding are defined only by DataCanon Core Version 1, not by Shorthand formatting.
External resources
Relative paths
Shorthand writes a DataCanon relative path as one quoted String whose components are joined by the ASCII slash (/). The parser splits that String on / to reconstruct the abstract DataCanon relative path.
Each component MUST satisfy the relative-path invariants of DataCanon Core Version 1. In particular, empty components, . and .., and components containing backslashes are invalid.
Parsing an external DCI does not access its external resource.
ExternalFile
external_file("inputs/INCAR", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
The first argument is a relative path String. The second is a quoted hexadecimal SHA-256 digest decoding to exactly 32 bytes. A renderer SHOULD use 64 lowercase hexadecimal characters. A conforming parser MUST accept that spelling and MAY accept uppercase hexadecimal digits. Whitespace within a hexadecimal digest String is not part of the portable normative spelling.
ExternalArray
external_array("data/forces.bin", "float64", (100, 3), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
The arguments, in order, are a relative path String, a portable Array type String, a Tuple of nonnegative Integer dimensions, and a quoted SHA-256 digest decoding to exactly 32 bytes.
The external byte stream is defined by DataCanon Core Version 1. Shorthand carries the path, Array type, shape, and digest, but not the external contents.
Rendering requirements
A conforming renderer MUST satisfy, for every valid DCI x:
parse_shorthand(render_shorthand(x)) = x
Here equality means DCI equality as defined by DataCanon Core Version 1. The equation describes the behavior of conforming parser and renderer operations, not mandated function names in other programming languages.
Shorthand and longhand
Longhand is the form of Shorthand that uses explicit constructors for
structured values and ordinary literals for Null, Boolean, Integer, Float,
and String. For example, sum(1, 1.0, fraction(1, 2)) is longhand: the
integer and floating-point literals already identify their DCTs. Longhand
does not wrap literals as integer(1), float(1.0), or string("hello");
those wrappers are not part of the Version 1 grammar.
The distinction is syntactic, not the Core classification of primitive,
atomic, and composite DCTs. Fraction and Constant are primitive but use fraction(...) and
constant(...), respectively, in longhand. Longhand is a subset of the same grammar, accepted by the same
parser. Shorthand permits constructors and shorter spellings to be freely
mixed. No additional fully wrapped rendering mode is defined.
The Python renderer accepts longhand=False (the default) or longhand=True.
With False, it uses shorter spellings where appropriate, falling back to
constructors to preserve structure. With True, it produces longhand.
The option MUST be a Boolean. Longhand selection is independent of layout
layout, alignment, and indentation. Both settings produce valid
strict Shorthand representing equal DCIs.
| DCT | Shorthand examples | Longhand |
|---|---|---|
| Fraction | 1/2 | fraction(1, 2) |
| List | [1, 2] | list(1, 2) |
| Tuple | (1, 2) | tuple(1, 2) |
| Set | {1, 2} | set(1, 2) |
| Mapping | {"a": 1} | mapping("a": 1) |
| Sum | 1 + 2 | sum(1, 2) |
| Product | 2 * sqrt(3) | product(2, power(3, 1, 2)) |
| Power | 5**2, 5**(1/3), or sqrt(5) | power(5, 2), power(5, 1, 3), or power(5, 1, 2) |
Longhand applies recursively to constituent DCIs. Null, Boolean, Integer,
Float, and String retain their literal spellings. Fraction uses fraction(...)
even though it is classified as primitive; Bytes retains bytes("...").
Constructs having only one spelling retain that spelling.
Array bodies continue to use their specialized element syntax; their brackets
do not represent List DCIs. Shape Tuples may use either Tuple spelling.
Shorthand rendering MUST use constructors wherever necessary to preserve identity.
In particular, empty and singleton Sums and Products retain constructors;
nested Sums and Products MUST NOT be flattened by rendering. A Sum used as a
Product operand requires an explicit constructor because Shorthand does not
provide general grouping parentheses. Fraction bases, signed literal bases,
and complicated bases may use power(...) to avoid precedence ambiguity.
Multiline output may also use constructors for clearer layout.
For example:
1 + sum(2, 3)
2 * product(3, 4)
2 * sum(3, 4)
power(1/2, 3)
Longhand selection and any constructor fallback do not participate in DCI identity or canonical binary encoding.
Renderers MAY choose their own whitespace, indentation, line breaking, column alignment, and compactness policies. The Python binding’s formatting options are not distinct dialects or normative cross-language layout requirements.
The Python binding provides independent layout, align, indent, and
padding options, plus custom_layout per-type overrides. For multiline output,
standard places both delimiters on separate lines, semi-compact shares the
opening line with the first item or entry, and compact also shares the closing
line with the final content. inline forces the selected value and all its
descendants onto one line. An enclosing inline requirement overrides child
layout selections and disables table alignment within that subtree.
Indentation controls structural nesting on new lines, defaulting to two spaces.
Padding controls same-line gaps beside collection and constructor delimiters,
defaulting to one space, including flat values. Shared-opener continuation
items align with the first item at relative column len(opening) + padding;
indentation does not add another gap there. Standard multiline delimiters
receive no padding because they occupy separate lines. Compact shared closers
receive the requested padding before them. Both options are nonnegative
integers. Primitive literal forms and specialized Array element syntax remain
unchanged; Array constructors can still be rendered inline.
Lists, Tuples, Sets, and Multisets normally become multiline when they directly contain a List or Tuple, or an item already spanning multiple lines. Inline layout overrides that rule. Rectangular List/Tuple rows can be aligned inside any of those four collection types. Empty collections retain their empty forms. All layout choices preserve DCI identity and the same strict grammar; the Python API specifies their precise presentation behavior.
Renderers MUST NOT normalize numerical structures mathematically, erase Float signed zero, reorder ordered collections, or change any other constituent that participates in DCI identity.
A renderer of an unordered collection MAY choose any entry/member order accepted by the strict parser. The canonical ordering of the binary encoding does not impose a textual ordering requirement.
Invalid input and error handling
A conforming parser MUST reject malformed syntax, unsupported identifiers, invalid numeric values, invalid escape sequences, duplicate keys or fields, invalid Array shapes or types, invalid external paths or digests, and input remaining after a complete DCI has been parsed.
An implementation MAY use its own error types and diagnostics. No specific error-message text is required by this specification.
Implementations MAY impose resource limits on text size, nesting depth, Array allocation, or integer magnitude. Such limits are implementation constraints and do not change DCI identity.
Relationship to other DataCanon specifications
- DataCanon Core V1 defines the DCTs, equality, canonical encoding, and fingerprinting.
- Shorthand Preprocessing V1 (separate document) will define compact List notation, general substitutions, and restricted scalar
eval(...)transformations before strict parsing. - YAML Interchange V1 (separate document) may embed strict Shorthand using the
$convention. - HDF5 V1 and Persistence V1 (separate documents) will define storage and external-resource conventions.
Neither the preprocessor nor a persistence mechanism alters the strict Shorthand grammar defined here.
Appendix A — Conformance examples
The conformance examples identify the DCT or property that a conforming strict parser MUST recover. They are not prescribed renderer output.
| Input | Expected result |
|---|---|
null | Null |
false | Boolean false |
-42 | Integer -42 |
-0.0 | Float negative zero |
bytes("") | Empty Bytes |
bytes("00FF") | Bytes containing 00 ff |
"a\\nb" | String with a line feed |
2/4 | Fraction with numerator 2, denominator 4 |
sum(1, 1, 2) | Sum retaining duplicate terms |
1/2 * sqrt(3) | Product containing Fraction and Power |
sqrt(3) | Power with numerator 1 and denominator 2 |
power(5, 2) | Power with denominator 1 |
quotient(1, sum(2, 3)) | Quotient with a Sum denominator |
complex(1, 2.0) | Complex(Integer, Float) |
[] | Empty List |
() | Empty Tuple |
(1) | One-element Tuple |
{} | Empty Mapping |
set() | Empty Set |
{1, 2} | Two-member Set |
multiset() | Empty Multiset |
multiset(1, 1, 2) | Multiset with three occurrences |
multiset(2, 1, 1) | Equal to multiset(1, 1, 2) |
multiset(1,) | Multiset with one occurrence |
{"a": 1, "b": 2} | Ordered Mapping |
umapping("b": 2, "a": 1) | UnorderedMapping |
record("Point", "x": 1) | Record |
array([1.0, 2.0]) | Array with inferred portable type and shape |
The following are invalid strict Shorthand:
1 2
'hello'
+1
1/0
1/-2
-sqrt(2)
power(5, 0)
power(5, 1, 0)
5**2**3
1/2**3
1/2**(1/3)
quotient(1)
sum(true)
{1, 1}
{"a": 1, "a": 2}
array([1.0 + 2.0j])
Appendix B — Outstanding Version 1 finalization items
The finalization items are deliberately recorded rather than silently resolved by assumptions about other languages:
- Pin the NumPy reference version governing Array inference, dtype conversion, and shape construction. This is the principal remaining cross-language portability dependency.
- Decide whether NumPy dtype aliases beyond the 14 portable Array type names are normative input or only permissive Python extensions.
- Confirm the exact treatment of optional noncanonical hexadecimal digest spellings, if interoperability with hand-authored external references warrants it.
- Publish cross-implementation vectors pairing Shorthand input with canonical Core V1 bytes, especially for Arrays, compositional numerical types, and external references.
None of these items changes the 24 core DCT definitions or the Core V1 canonical byte encoding.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.