The generated Show
Show is generated for every type without being written, and its text is fixed so that two implementations of the language print the same thing for the same value.
Show turns a value into the String a reader sees: what print writes, and what "{value}" puts into an
interpolation. Every type gets one for free, in a format that is part of the language rather than of one
implementation, so the same value prints the same way whichever back end produced it.
Example#
type Card {
label: String
initial: Char
}
const card = Card label: "Ada", initial: 'A'
print card
print "{card}"
print([card, card])Syntax#
value.show(): String
"{value}" // Uses show(), or showNested() where value sits inside another value's ShowRules#
A
typeshows asType(field: value, ...), every field in declaration order.Card(label: "Ada", initial: 'A')- the same text
copyand the constructor would take back.
- the same text
Every field is in it,
privateones included, wherever the value is printed.Showis the debug form of a value andEqualsandHashread the same fields, so hiding one here would make a printed value disagree with what the type is. A type whose field is a secret writes its ownShowinstead of relying on the generated one.type Email { private value: String } print Email("info@example.test") // Email(value: "info@example.test")A case shows as
Case(field: value, ...), or its bare name when it has none.type Shape { case Circle(radius: Float) case Empty } print Shape.Circle(2.0) // Circle(radius: 2.0) print Shape.Empty // EmptyA collection has its own bracket, not the type's. A
Listis[a, b], aMapis["k": v]and[:]when it is empty. Both come from the collection's ownShow, generated from the same fixed shapes so a value inside one nests correctly.print([1, 2, 3]) print(["a": 1, "b": 2])Inside another value's
Show, onlyStringandChardiffer from their ownshow(). AStringis quoted with escapes and aCharis in single quotes, so["a", "b"]stays readable while"{name}"is still the text itself with nothing added around it.print "Ada" // Ada print(["Ada", "Grace"]) // ["Ada", "Grace"]Optionshows asSome(x)orNone. These are the same names the value is matched with, so a printed value and a pattern for it read the same way.A
Floatalways carries a decimal point or an exponent.1.0shows as1.0, never1, so a reader can tell aFloatfrom anInton sight.-0.0keeps its sign, and a division by zero shows asinf,-infornan.A function value shows as its type, spelled as a type annotation spells it.
(Int64) => Int64, with no parameter names and nothing of what the closure captured, so every function of one type prints the same.type Handler { name: String run: (Int) => Int } const increment = { value: Int => value + 1 } print increment // (Int64) => Int64 print Handler("inc", increment) // Handler(name: "inc", run: (Int64) => Int64)
What this is not#
Show is not a proxy for identity. Two values print identically exactly when their fields do, which is a
statement about content - it says nothing about whether they are the same object, and isSame is a different
question with a different answer for two values that print the same.
type Card {
label: String
initial: Char
}
const a = Card label: "Ada", initial: 'A'
const b = Card label: "Ada", initial: 'A'
print a
print b
print(a == b)type Card {
label: String
initial: Char
}
const a = Card label: "Ada", initial: 'A'
const b = Card label: "Ada", initial: 'A'
print isSame(a, b)
// error: `isSame` compares identity, and a `Card` is a valueA Show is generated even where Equals and Hash are not: a function value has a Show of its own (a function
prints as its type, rule 8), so a function-typed field keeps a type from getting Equals, Hash and copy without
touching its Show - copy and equality shows the Equals side of that.
Related#
- Declaring a type - where
Showis introduced alongsideEquals,Hashandcopy. - Copy and equality - the other members that are generated together with
Show. - Cases and match - the case syntax
Showmirrors.