The Bosque language is a hybrid of functional programming language semantics and an ergonomic block & assignment-based syntax. This allows developers to organize code into familiar/natural blocks and compositions while, simultaneously, benefiting from the correctness and simplicity of a functional programming model.
- Primitive Types
- Nominal Types
- Structural Types
- Code Block Types
- Combination Types
- Ephemeral Lists
- Containers
- 5.3 Variable and Scoped Access
- 5.4 Tuple and Record Constructors
- 5.5 Entity Constructors
- 5.6 PCode Constructors
- 5.7 Scoped Invokes
- 5.8 None-Chaining
- 5.9 Tuple Typed Access Operators
- 5.10 Record Typed Access Operators
- 5.11 Nominal Typed Access Operators
- 5.12 Typed Projection
- 5.13 Update
- 5.14 Merge
- 5.15 PCode Apply
- 5.17 Unary Operators
- 5.18 Binary Operators
- 5.19 Equality Comparison
- 5.20 Order Comparison
- 5.21 Logic Operators
- 5.22 None Coalescing
- 5.23 Select
- 5.24 Statement Expressions
- 5.25 Synthesis Blocks
- 6.1 Empty
- 6.2 Variable Declaration
- 6.3 Variable Assignment
- 6.4 Structured Declaration and Assignment
- 6.5 Return and Yield
- 6.6 Validation
- 6.7 If-Then-Else
- 6.8 Switch
- 6.9 Block
- 6.9 Statement Calls
The Bosque language supports a simple and non-opinionated type system that allows developers to use a range of structural, nominal, and combination types to best convey their intent and flexibly encode the relevant features of the problem domain. All type names must start with a capital letter - MyType
is a valid type name while myType
is not. Template type names are single capital letters -- T
, V
, etc.
Bosque provides a range of standard primitive types, numerics, strings, times, etc. as part of the core implementation.
- None: The type
None
is the special primitive none-able type that has the single (unique)none
value. - Nothing: The type
Nothing
special primitive nothingOption<T>
type that has the single (unique)nothing
value. - Bool: The type
Bool
is contains the specialtrue
andfalse
values. - Nat & Int: The
Nat
andInt
types represent unsigned and signed (respectively) 64 bit numbers. Overflows, underflows, and div-by-0 all raise fatal errors. - BigNat & BigInt: The
BigNat
andBigInt
types represent unsigned and signed (respectively) unbounded integral numbers. Underflows and div-by-0 raise fatal errors while overflows are either limited to an implementation defined max (at least 256 bits or Out-of-Memory) and saturating operations++
,--
,**
are provided (TODO). - Float & Decimal: The
Float
type is a 64 bit IEEE-754 floating point number. TheDecimal
type is a 64 bit decimal floating point number. - Rational: The
Rational
type is a rational representation of a number with aBigInt
valued numerator and aNat
valued (non-zero) denominator. Overflow in the denominator is handled by rounding to the nearest representable value. - String: The
String
type in Bosque is a utf-8 unicode string. Notably this string type does not support arbitrary indexing (which is undefined for utf-8 multibyte characters). Instead operations must use regex based slicing, extraction, etc. - ASCIIString: (TODO) The
ASCIIString
type is a ASCII char based string that can be meaningfully processed using integral index operations. - ByteBuffer: The
ByteBuffer
type is a 0 indexed array of uninterpreted 8 bit values. - Regex: the
Regex
type is the type assigned to all regex literals in the program.
In addition to the basic types enumerated above, Bosque also provides a range of commonly useful types for dealing with time, locations, events, and identity.
- DateTime: The
DateTime
type represents a human scale time with minute precision (so no leap second issues). The representation is TimeZone based and does not allow naive comparision for ordering or computation of offsets as these are ill defined and non-deterministic operations (e.g. when the times are in the future a TZ meaning may change). - UTCDateTime: The
UTCDateTime
type is a specialized version ofDateTime
that is fixed at UTC for the timezone. This allows us to do direct ordering and arithmetic on the dates. - CalendarDate: The
CalendarDate
type is a date only value, month, day, year, so it is free of TZ related complications and can be directly ordered and used for offset date computation. - TickTime: the
TickTime
type is a 54 bit, nano-second interval, epoch based time TAI derived. This time is monotone and corresponds to real elapsed time. - LogicalTime: the
LogicalTime
type is a logical tick based time useful for causal ordering events in a system. - ISOTimeStamp: the
ISOTimeStamp
type is a ISO 8061 timestamp with milliseconds and a timezone. It is intended to be used for legacy interop and for human friendly timestamps in logs or other records. Historical values are stable but future values may be unstable as time-zone changes or leap-seconds are added. - UUID4 & UUID7: the UUID types for
UUID4
andUUID7
are natively supported in Bosque. - SHAContentHash: the
SHAContentHash
type is a SHA3 512 bit hash code. Bosque has support (TODO) for computing SHA hashes of any value and can produce a result of typeSHAContentHash
orSHAContentHashOf<T>
. - LatLongCoordinate:: the
LatLongCoordinate
is a decimal degree encoding (6 decimal digits) of a latitude and longitude value.
The nominal type system is a mostly standard object-oriented design with parametric polymorphism provided by generics. Bosque also supports type aliasing typedef
and wrapping of primitive types with typedecl
.
Entities are concrete object-oriented style (member fields, methods, etc.) types that can be created. An entity will never have another type that is a strict subtype of it! Entities are always subtypes of the special Some
and Any
concepts and user defined entities are always subtypes of the special Object
concept. Entities can be declared as polymorphic with template parameters. In Bosque templates are not parametric in their instantiated types -- e.g. List<Int>
is not a subtype of List<Any>
.
Entity type references are simply the (scoped) name of the type such as Foo
for a locally scoped type or Bar::Foo
, Bar::Baz::Foo
for a type Baz
declared in the given scope (namespace or type scope). Entity types may also be parametric, such as List<Int>
or Foo<Bool, Map<Int, Int>>
.
In Bosque the typedef
declaration can be used to create a nominal alias for any type. This alias is not a distinct type and, in type checking and execution, is replaced by the underlying aliased type (see also typedecl
below).
There are several special entity types in Bosque:
- Enum: Bosque supports
enum
types as nominal types. The underlying values can be any typedeclable type but the enum type is always a distinct type in the program. - typedecl: To create a new and distnct nominal type for any typedeclable type the
typedecl
keyword can be used to create a new type that is has an identical value representation (accessable via thevalue
method) to the underlying type but is a distinct type in the program. - StringOf<T> & DataString<T>: The
StringOf<T>
andDataString<T>
types in the program (alsoASCIIStringOf<T>
andASCIIDataString<T>
types) are dsistinct string types. The StringOf flavors are parameterized by Validator regexes (the underlying string is in the specified language) while the DataString flavors are parameterized by types that provide theParsable
concept (i.e. they have anaccepts
function). - DataBuffer<T>: The
DataBuffer<T>
type is similar to theDataString<T>
type except the underlying value is aByteBuffer
. - Something<T>: is the subtype of
Option<T>
that represents a value (as opposed to the specialNothing
subtype). There is a special constructor operatorsomething
that can be used as a type infering constructor in addition to explicit construction. - Result<T, E>::Ok & Result<T, E>::Err: Bosque provides a standard
Result<T, E>
concept withOk
andErr
entities. If omitted from the type the errorE
type is assumed to beNone
. As withSomething<T>
there are special (shorthand) type inferring keywordsok
anderr
for constructing these types.
Bosque also provides a range of built-in container types List<T>
, Stack<T>
, Queue<T>
, Set<T>
, and Map<K, V>
which are described in more detail in the libraries document.
Bosque concept types are fully abstract and can never be instantiated concretely. Concepts can be provided by concrete entities in the program. Concept types can define virtual or concrete methods, fields, and constants. Concepts are referenced by names (just like entities) such as Some
, Result<Int>
, etc.
There are several special concept types in Bosque:
- Any: The
Any
type is an ur concept that every type in Bosque is a subtype of. - Some: The
Some
type is a concept type that every non-none type is a subtype of. - KeyType: The
KeyType
concept is a critical type in Bosque. The===
and!==
operator are defined to work only on such types and keys inSet<T>
andMap<K, V>
must be subtypes ofKeyType
. The list of keytypes and mor information on their behavior is included in the KeyType section. - APIType: The special
APIType
concept is used to identify which types can/are exposed inentrypoint
functions. These types are ensured to be 1) convertible to work in polyglot environments and 2) are amenable to structured generation for fuzzing and testing. See the APIType & TestableType section for more detail. - TestableType: The special
TestableType
concept is used to identify which types can/are exposed in unit-test functions. This is similar to theAPIType
concept but used for types that are not intended to be publicly exposed (just visible for testing purposes). See the APIType & TestableType section for more detail. - Option: Bosque supports a familiar
Option<T>
concept for convenient use of sentinel missing values (nothing
). - Result<T, E>: Bosque supports a standard
Result<T, E>
type for convenient result value management. When not explicitly provided the error (E
) type defaults toNone
. - Object: All user defined entities implicitly provide the
Object
concept.
Concept types can be stacked, via the &
combinator, to indicate a value/variable should provide multiple concepts. So, the type reference KeyType & APIType
indicates that the type provide both the KeyType
concept and the APIType
concept.
XXXX
XXXX
XXXX
XXXX
Bosque supports a standard set of logical operations on Bool
typed values:
!
is a negation of aBool
value.&&
is a short circuiting logical and of twoBool
values.||
is a short circuiting logical or of twoBool
values.==>
is a short circuiting logical implies ofBool
values -- note that&&
and||
bind tighter tha==>
when parsing logical expressions.
!true //false
!false //true
!0 //type error
true && false //false
true && true //true
false && (1n / 0n) == 1n //false -- short circuit is safe
true || false //true
false || false //false
true || (1n / 0n) == 1n //true -- short circuit is safe
true ==> false //false
true ==> true //true
false ==> true //true (antecedent is false)
false ==> (1n / 0n) == 1n //true -- short circuit is safe
In some cases (i.e. to avoid branching or for clarity) it is desireable to use non-short-circuiting logical operations. Thus, Bosque also provides an:
/\(...)
is a logical and of all arguments (semantically evaluated simultaneously).\/(...)
is a logical or of all arguments (semantically evaluated simultaneously).
/\(true, false, true) //false
/\(true, true) //true
/\(false, (1n / 0n) == 1n) //runtime error -- no short circuit
\/(true, false, true) //true
\/(false, false) //false
\/(true, (1n / 0n) == 1n) //runtime error -- no short circuit
Bosque supports a range of comparison operators, ==
, !=
,<
, >
, <=
, and >=
which can be applied to numeric values -- Nat
, Int
, BigNat
, BigInt
, Float
, Decimal
, and Rational
values as well as orderable typedecl
based types (e.g. orderable typedecl ItemCount = Int;
) based on them.
0i == 1i //false
1i == 1i //true
0n < 5n //true
0n < 5i //type error not same types
10_ItemCount >= 0_ItemCount //true
The (numeric) comparison operators in Bosque are implemented as static operators and so can be extended by user defined types as well.
entity Complex {
field r: Float;
field i: Float;
}
infix operator ==(a: Complex, b: Complex): Bool {
return a.r == b.r && a.i == b.i;
}
infix operator !=(a: Complex, b: Complex): Bool {
return a.r != b.r || a.i != b.i;
}
...
Complex{1.0f, 0.0f} != Complex{1.0f, 1.0f} //true
Then calls where the LHS and RHS arguments resolve to Complex
types will resolve to this implementation transparently.
Bosque supports a range of numeric arithmetic operators, +
, -
,*
, /
, <=
which can be applied to numeric values -- Nat
, Int
, BigNat
, BigInt
, Float
, Decimal
, and Rational
values as well as algebraic typedecl
based types (e.g. algebraic typedecl ItemCount = Int;
) based on them. The signed types also support unary negation -x
.
0i + 1i //1i
1i - 1i //0i
3n * 5n //15n
3n / 2n //1n
3.0f / 2.0f //1.5f
0n + 5i //type error not same types
10_ItemCount + 1_ItemCount //11_ItemCount
10_ItemCount * 2i //20_ItemCount
10_ItemCount / 5_ItemCount //2i
In xxxx;
The (numeric) comparison operators in Bosque are implemented as static operators and so can be extended by user defined types as well (TODO: see issue for dynamic vs. static operator).
entity Complex {
field r: Float;
field i: Float;
}
infix operator +(a: Complex, b: Complex): Complex {
return Complex{a.r + b.r, a.i + b.i};
}
infix operator *(a: Complex, b: Float): Complex {
return Complex{a.r * b, a.i + b};
}
infix operator *(a: Complex, b: Complex): Complex {
let rpart = a.r * b.r - a.i * b.i;
let ipart = a.r * b.i + a.i * b.r;
return Complex{rpart, ipart};
}
...
Complex{1.0f, 0.0f} + 2.0f //Complex{2.0f, 0.0f}
Complex{1.0f, 0.0f} + Complex{0.0f, 1.0f} //Complex{1.0f, 1.0f}
Then calls where the LHS and RHS arguments resolve to Complex
types will resolve to this implementation transparently.