silo:std.traits

Source src/silo:std.traits

1##! Foundational traits for arithmetic, comparison, conversion, and formatting.
2##!
3##! Declares the lang-bound traits used throughout the stdlib
4##! (`Add` / `Sub` / `Mul` / `Div`, `Eq` / `Ord`, `Not`, `From` /
5##! `Into`, `TryFrom` / `TryInto`, `Display` / `Debug`, `Hash`,
6##! `Default`, `Error`, `LowerHex`, `Binary`) and wires primitive-type
7##! impls to host intrinsics.
8
9:use
10  :open core AnyInt AnyFloat Bool Str Symbol Unit Result Vec Ordering Less Equal Greater
11:end
12
13# Arithmetic traits — host provides impls for primitive types.
14# Method names stay as operator symbols (`.+`, `.-`, etc.) to keep the
15# surface `+` working via op_to_traits trait dispatch. Spec targets
16# prose names (`.add`) + prelude :fn wrappers per si[trait.operator-fn],
17# but that migration blocks on checker trait-generic specialization.
18
19## Binary addition. Produces a `result` type that may differ from `Self` and `rhs` (e.g. Int + Float → Float). `.zero` returns the additive identity for the result type.
20@lang(add)
21:trait(pub) Add rhs | result
22  ## Add two values, producing a result whose type is determined by the impl.
23  .+ ( Self rhs -> result )
24  ## The additive identity — value that leaves any sum unchanged.
25  .zero ( -> result )
26:end
27
28## Binary subtraction. Mirrors `Add` in widening; result type MAY differ from `Self` / `rhs`.
29@lang(sub)
30:trait(pub) Sub rhs | result
31  ## Subtract `rhs` from `Self`, producing a result whose type is determined by the impl.
32  .- ( Self rhs -> result )
33:end
34
35## Binary multiplication. `.one` returns the multiplicative identity for the result type.
36@lang(mul)
37:trait(pub) Mul rhs | result
38  ## Multiply two values, producing a result whose type is determined by the impl.
39  .* ( Self rhs -> result )
40  ## The multiplicative identity — value that leaves any product unchanged.
41  .one ( -> result )
42:end
43
44## Binary division. Impl MAY partition into integer / float / exact-fraction flavours.
45@lang(div)
46:trait(pub) Div rhs | result
47  ## Divide `Self` by `rhs`, producing a result whose type is determined by the impl.
48  ./ ( Self rhs -> result )
49:end
50
51:impl Add AnyInt AnyInt | AnyInt
52  @host
53  .+ ( AnyInt AnyInt -> AnyInt ) ;
54  .zero ( -> AnyInt ) 0 ;
55:end
56:impl Add AnyFloat AnyFloat | AnyFloat
57  @host
58  .+ ( AnyFloat AnyFloat -> AnyFloat ) ;
59  .zero ( -> AnyFloat ) 0.0 ;
60:end
61:impl Add AnyInt AnyFloat | AnyFloat
62  @host
63  .+ ( AnyInt AnyFloat -> AnyFloat ) ;
64  .zero ( -> AnyFloat ) 0.0 ;
65:end
66:impl Add AnyFloat AnyInt | AnyFloat
67  @host
68  .+ ( AnyFloat AnyInt -> AnyFloat ) ;
69  .zero ( -> AnyFloat ) 0.0 ;
70:end
71:impl Add Str Str | Str
72  @host
73  .+ ( Str Str -> Str ) ;
74  .zero ( -> Str ) "" ;
75:end
76
77:impl Sub AnyInt AnyInt | AnyInt
78  @host
79  .- ( AnyInt AnyInt -> AnyInt ) ;
80:end
81:impl Sub AnyFloat AnyFloat | AnyFloat
82  @host
83  .- ( AnyFloat AnyFloat -> AnyFloat ) ;
84:end
85:impl Sub AnyInt AnyFloat | AnyFloat
86  @host
87  .- ( AnyInt AnyFloat -> AnyFloat ) ;
88:end
89:impl Sub AnyFloat AnyInt | AnyFloat
90  @host
91  .- ( AnyFloat AnyInt -> AnyFloat ) ;
92:end
93
94:impl Mul AnyInt AnyInt | AnyInt
95  @host
96  .* ( AnyInt AnyInt -> AnyInt ) ;
97  .one ( -> AnyInt ) 1 ;
98:end
99:impl Mul AnyFloat AnyFloat | AnyFloat
100  @host
101  .* ( AnyFloat AnyFloat -> AnyFloat ) ;
102  .one ( -> AnyFloat ) 1.0 ;
103:end
104:impl Mul AnyInt AnyFloat | AnyFloat
105  @host
106  .* ( AnyInt AnyFloat -> AnyFloat ) ;
107  .one ( -> AnyFloat ) 1.0 ;
108:end
109:impl Mul AnyFloat AnyInt | AnyFloat
110  @host
111  .* ( AnyFloat AnyInt -> AnyFloat ) ;
112  .one ( -> AnyFloat ) 1.0 ;
113:end
114
115:impl Div AnyInt AnyInt | AnyInt
116  @host
117  ./ ( AnyInt AnyInt -> AnyInt ) ;
118:end
119:impl Div AnyFloat AnyFloat | AnyFloat
120  @host
121  ./ ( AnyFloat AnyFloat -> AnyFloat ) ;
122:end
123:impl Div AnyInt AnyFloat | AnyFloat
124  @host
125  ./ ( AnyInt AnyFloat -> AnyFloat ) ;
126:end
127:impl Div AnyFloat AnyInt | AnyFloat
128  @host
129  ./ ( AnyFloat AnyInt -> AnyFloat ) ;
130:end
131
132# Comparison traits.
133
134## Equality comparison. `.≠` defaults to the negation of `.=`; impls SHOULD override only for performance.
135@lang(eq)
136:trait(pub) Eq other
137  ## Test whether two values are equal.
138  .= ( Self other -> Bool )
139  ## Test whether two values are not equal. Default: negation of `.=`.
140  .≠ ( Self other -> Bool )
141    .= not ;
142:end
143:impl Eq AnyInt AnyInt
144  @host
145  .= ( AnyInt AnyInt -> Bool ) ;
146  @host
147  .≠ ( AnyInt AnyInt -> Bool ) ;
148:end
149:impl Eq AnyFloat AnyFloat
150  @host
151  .= ( AnyFloat AnyFloat -> Bool ) ;
152  @host
153  .≠ ( AnyFloat AnyFloat -> Bool ) ;
154:end
155:impl Eq Bool Bool
156  @host
157  .= ( Bool Bool -> Bool ) ;
158  @host
159  .≠ ( Bool Bool -> Bool ) ;
160:end
161:impl Eq Str Str
162  @host
163  .= ( Str Str -> Bool ) ;
164  @host
165  .≠ ( Str Str -> Bool ) ;
166:end
167:impl Eq Symbol Symbol
168  @host
169  .= ( Symbol Symbol -> Bool ) ;
170:end
171
172## Total ordering. `.≤` defaults to `not .>`; `.≥` defaults to `not .<`. Impls SHOULD provide a cheaper `.cmp`-based form when available.
173@lang(ord)
174:trait(pub) Ord other
175  ## Strict less-than.
176  .< ( Self other -> Bool )
177  ## Strict greater-than.
178  .> ( Self other -> Bool )
179  ## Less-than-or-equal. Default: negation of `.>`.
180  .≤ ( Self other -> Bool )
181    .> not ;
182  ## Greater-than-or-equal. Default: negation of `.<`.
183  .≥ ( Self other -> Bool )
184    .< not ;
185:end
186:impl Ord AnyInt AnyInt
187  @host
188  .< ( AnyInt AnyInt -> Bool ) ;
189  @host
190  .> ( AnyInt AnyInt -> Bool ) ;
191  @host
192  .≤ ( AnyInt AnyInt -> Bool ) ;
193  @host
194  .≥ ( AnyInt AnyInt -> Bool ) ;
195:end
196:impl Ord AnyFloat AnyFloat
197  @host
198  .< ( AnyFloat AnyFloat -> Bool ) ;
199  @host
200  .> ( AnyFloat AnyFloat -> Bool ) ;
201  @host
202  .≤ ( AnyFloat AnyFloat -> Bool ) ;
203  @host
204  .≥ ( AnyFloat AnyFloat -> Bool ) ;
205:end
206:impl Ord Str Str
207  @host
208  .< ( Str Str -> Bool ) ;
209  @host
210  .> ( Str Str -> Bool ) ;
211  @host
212  .≤ ( Str Str -> Bool ) ;
213  @host
214  .≥ ( Str Str -> Bool ) ;
215:end
216:impl Ord Symbol Symbol
217  @host
218  .< ( Symbol Symbol -> Bool ) ;
219  @host
220  .> ( Symbol Symbol -> Bool ) ;
221:end
222
223# Logic trait.
224
225## Logical or bitwise negation. For `Bool` this is logical NOT; for integer types it is bitwise NOT.
226@lang(not)
227:trait(pub) Not .not ( Self -> Self ) :end
228:impl Not Bool
229  @host
230  .not ( Bool -> Bool ) ;
231:end
232
233# Prelude operators. Spec si[trait.operator-fn] targets :fn wrappers that
234# dispatch via trait methods; until the checker specializes such wrappers,
235# these operator symbols map directly to the same host intrinsics as the
236# trait methods they parallel (see ALIAS_RUNTIME_INTRINSICS).
237
238# Conversion traits.
239
240## Infallible construction of `Self` from a `source` value. Dual of `Into`.
241@lang(from)
242:trait(pub) From source .from ( source -> Self ) :end
243
244## Infallible conversion of `Self` into a `target` type. Blanket-impl'd from `From`.
245@lang(into)
246:trait(pub) Into target .into ( Self -> target ) :end
247
248## Fallible construction of `Self` from a `source` value; returns `(Result Self error)`.
249## `error` is associated — each impl fixes its own error type.
250:trait(pub) TryFrom source | error .try-from ( source -> (Result Self error) ) :end
251
252## Fallible conversion of `Self` into a `target` type; returns `(Result target error)`.
253## `error` is associated — dual of `TryFrom`.
254:trait(pub) TryInto target | error .try-into ( Self -> (Result target error) ) :end
255
256:impl From AnyFloat AnyInt .from ( AnyInt -> AnyFloat ) int>float ; :end
257:impl Into AnyInt AnyFloat .into ( AnyInt -> AnyFloat ) int>float ; :end
258:impl From AnyInt AnyInt .from ( AnyInt -> AnyInt ) identity ; :end
259:impl Into AnyInt AnyInt .into ( AnyInt -> AnyInt ) identity ; :end
260:impl From AnyFloat AnyFloat .from ( AnyFloat -> AnyFloat ) identity ; :end
261:impl Into AnyFloat AnyFloat .into ( AnyFloat -> AnyFloat ) identity ; :end
262:impl From Bool Bool .from ( Bool -> Bool ) identity ; :end
263:impl Into Bool Bool .into ( Bool -> Bool ) identity ; :end
264:impl From Str Str .from ( Str -> Str ) identity ; :end
265:impl Into Str Str .into ( Str -> Str ) identity ; :end
266:impl From Symbol Symbol .from ( Symbol -> Symbol ) identity ; :end
267:impl Into Symbol Symbol .into ( Symbol -> Symbol ) identity ; :end
268
269# Display trait — method renamed from `.show` to `.fmt` per spec/traits.md
270# si[trait.display]. FmtSpec parameter arrives with Phase 3.
271# si[impl lang.display+1]
272
273## User-facing formatted representation. For values that MAY appear in end-user messages, prefer `Display` over `Debug`.
274@lang(display)
275:trait(pub) Display .fmt ( Self -> Str ) :end
276:impl Display AnyInt .fmt ( AnyInt -> Str ) int>str ; :end
277:impl Display AnyFloat .fmt ( AnyFloat -> Str ) float>str ; :end
278:impl Display Bool .fmt ( Bool -> Str ) bool>str ; :end
279:impl Display Str .fmt ( Str -> Str ) identity ; :end
280:impl Display Symbol .fmt ( Symbol -> Str ) symbol>str ; :end
281
282# Debug trait — method renamed from `.debug` to `.fmt-debug`.
283# si[impl lang.debug+1]
284
285## Diagnostic formatted representation intended for developers. MAY reveal internal structure that `Display` hides.
286@lang(debug)
287:trait(pub) Debug .fmt-debug ( Self -> Str ) :end
288:impl Debug AnyInt .fmt-debug ( AnyInt -> Str ) int>str ; :end
289:impl Debug AnyFloat .fmt-debug ( AnyFloat -> Str ) float>str ; :end
290:impl Debug Bool .fmt-debug ( Bool -> Str ) bool>str ; :end
291:impl Debug Str .fmt-debug ( Str -> Str ) identity ; :end
292:impl Debug Symbol .fmt-debug ( Symbol -> Str ) symbol>str ; :end
293
294# Hash trait — kept at simple Self→AnyInt shape; hasher-polymorphic form
295# (si[trait.hash+1]) arrives with the Hasher trait in a later phase.
296# si[impl lang.hash+1]
297
298## Produce a 64-bit hash of `Self`. Equal values MUST hash equal. Hasher-polymorphic shape arrives in a later phase.
299@lang(hash)
300:trait(pub) Hash .hash ( Self -> AnyInt ) :end
301:impl Hash AnyInt .hash ( AnyInt -> AnyInt ) hash-int ; :end
302:impl Hash AnyFloat .hash ( AnyFloat -> AnyInt ) hash-float ; :end
303:impl Hash Bool .hash ( Bool -> AnyInt ) hash-bool ; :end
304:impl Hash Str .hash ( Str -> AnyInt ) hash-str ; :end
305:impl Hash Symbol .hash ( Symbol -> AnyInt ) hash-symbol ; :end
306
307# Default trait. Effect-polymorphic shape per si[trait.default+1] arrives
308# when effect rows on nullary methods are wired (Phase 8).
309# si[impl lang.default+1]
310
311## Produce the canonical default value for `Self` (0 for numerics, `""` for `Str`, empty container, etc.).
312@lang(default)
313:trait(pub) Default .default ( -> Self ) :end
314:impl Default AnyInt .default ( -> AnyInt ) default-int ; :end
315:impl Default AnyFloat .default ( -> AnyFloat ) default-float ; :end
316:impl Default Bool .default ( -> Bool ) default-bool ; :end
317:impl Default Str .default ( -> Str ) default-str ; :end
318:impl Default Unit .default ( -> Unit ) default-unit ; :end
319:impl Default (Vec elem len)
320  .default ( -> (Vec elem len) ) vec-empty-intrinsic ;
321:end
322# `Default` for `HashMap` and `HashSet` lives in `collections.si` per
323# `si[coll.hashmap.hash-state+2]`: their `.default` body MUST draw a
324# `HashState` via `(HashState .new)`, which carries `+Random`. Putting
325# those impls here would require `HashState` to be declared before
326# `traits.si` loads, which reverses the current bootstrap order. The
327# impls land with the rest of the collection plumbing after
328# `HashState` is in scope.
329
330# Error trait.
331# si[impl lang.error+1]
332
333## Marker trait for error types. `.message` returns a human-readable short description suitable for end-user contexts.
334@lang(error)
335:trait(pub) Error .message ( Self -> Str ) :end
336
337# LowerHex trait — method renamed from `.hex` to `.fmt-hex`.
338
339## Lowercase hexadecimal formatting. Backs the `{:x}` format specifier.
340:trait(pub) LowerHex .fmt-hex ( Self -> Str ) :end
341:impl LowerHex AnyInt .fmt-hex ( AnyInt -> Str ) int>hex ; :end
342
343# Binary trait — method renamed from `.bin` to `.fmt-bin`.
344
345## Base-2 (binary) formatting. Backs the `{:b}` format specifier.
346:trait(pub) Binary .fmt-bin ( Self -> Str ) :end
347:impl Binary AnyInt .fmt-bin ( AnyInt -> Str ) int>bin ; :end