Objects (type)#

Meta: lead with "a type declares both a type and its prototype constructor." That's the unusual thing. Cross-link to Mutation and copy-on-write — don't try to explain CoW here.

Declaration#

type Person {
  name: String!
  age: Int! = 0

  greet: String! {
    "hi, I'm " + name
  }
}

Public vs. private members#

# `let` privacy is module-scoped, not type-scoped: another type in the same
# module reaches a let member (across a module boundary it is rejected)
type Account { let secret: String! = "hunter2" }
type Vault { unlock(a: Account!): String! { a.secret } }
Vault.unlock(Account)   # "hunter2"

Implicit constructor#

Person("Alice", age: 30)
Person(name: "Alice")

Zero-arg auto-construction#

Explicit constructor: new#

type Greeter {
  greeting: String!

  new(name: String!) {
    self.greeting = "hello, " + name
    self
  }
}

self#

Computed fields#

fullName: String! { firstName + " " + lastName }

Static members#

type Color {
  r: Int! = 0
  g: Int! = 0
  b: Int! = 0

  luminance: Int! { (r + g + b) / 3 }        # an instance member

  # a self { } block declares statics: they live on the type itself, reached as
  # Color.member, never on an instance
  self {
    white: Color! { Color(r: 255, g: 255, b: 255) }   # a factory method
    fromGray(v: Int!): Color! { Color(r: v, g: v, b: v) }
    grayMid: Color! { fromGray(128) }                 # a static calling a sibling static
    let scale = 2                                      # a private (let) static helper
    doubled(v: Int!): Int! { v * scale }
  }
}

Color.white.luminance          # 255
Color.fromGray(10).r           # 10
Color.grayMid.g                # 128
Color.doubled(7)               # 14
Color(r: 3, g: 6, b: 9).luminance   # 6 — instances are unaffected by statics
Color.luminance                # 0 — a bare all-default type still auto-constructs
# static stored fields hold singleton state on the type
type Config {
  host: String! = "localhost"
  self {
    limit: Int! = 100
    default: Config! = Config    # a static holding a constructed instance
  }
}

Config.limit          # 100
Config.default.host   # "localhost"

Implements#

type Person implements Named & Identifiable { name: String!; id: String! }

Forward references#

Meta: user-defined types and imported GraphQL input types share the same Type(args) construction syntax. Schema input types are constructed exactly like local types: CreateUserInput(name: "Alice", email: "...") passed as Mutation.createUser(input: ...). See GraphQL interop.