Created
March 16, 2025 09:33
-
-
Save johannes-riecken/8efdebb75e78c6045ae499115aea142a to your computer and use it in GitHub Desktop.
Code examples from "Definition-Checked Generics" talk at CppNow 2023
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface RNGInterface { | |
let Result: type; | |
fn Random[addr self: Self*]() -> Result; | |
} | |
class BaseRNGClass { ... } | |
class FancyRNG { | |
extend base: BaseRNGClass; | |
extend impl as RNGInterface where .Result = f64 { | |
fn Random[addr self: Self*]() -> f64 { ... } | |
} | |
} | |
fn GenericFunction[T:! RNGInterface](r: T*) -> T.Result { | |
return r->Random(); | |
} | |
interface RNGInterface { | |
let Result: type; | |
fn Random[addr self: Self*]() -> Result; | |
} | |
class BaseRNGClass { ... } | |
class FancyRNG { | |
extend base: BaseRNGClass; | |
extend impl as RNGInterface where .Result = f64 { | |
fn Random[addr self: Self*]() -> f64 { ... } | |
} | |
} | |
fn GenericFunction[T:! RNGInterface](r: T*) -> T.Result { | |
return r->Random(); | |
} | |
interface RNGInterface { | |
let Result: type; | |
fn Random[addr self: Self*]() -> Result; | |
} | |
class BaseRNGClass { ... } | |
class FancyRNG { | |
extend base: BaseRNGClass; | |
extend impl as RNGInterface where .Result = f64 { | |
fn Random[addr self: Self*]() -> f64 { ... } | |
} | |
} | |
fn GenericFunction[T:! RNGInterface](r: T*) -> T.Result { | |
return r->Random(); | |
} | |
interface RNGInterface { | |
let Result: type; | |
fn Random[addr self: Self*]() -> Result; | |
} | |
class BaseRNGClass { ... } | |
class FancyRNG { | |
extend base: BaseRNGClass; | |
extend impl as RNGInterface where .Result = f64 { | |
fn Random[addr self: Self*]() -> f64 { ... } | |
} | |
} | |
fn GenericFunction[T:! RNGInterface](r: T*) -> T.Result { | |
return r->Random(); | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point { | |
return {.x = self.x * scale, .y = self.y * scale}; | |
} | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(typeof(scale)).Op)(scale) | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point { | |
return {.x = self.x * scale, .y = self.y * scale}; | |
} | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(typeof(scale)).Op)(scale) | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point { | |
return {.x = self.x * scale, .y = self.y * scale}; | |
} | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(typeof(scale)).Op)(scale) | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point { | |
return {.x = self.x * scale, .y = self.y * scale}; | |
} | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(typeof(scale)).Op)(scale) | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point { | |
return {.x = self.x * scale, .y = self.y * scale}; | |
} | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(typeof(scale)).Op)(scale) | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
choice Ordering { | |
Less, | |
Equivalent, | |
Greater, | |
Incomparable | |
} | |
interface OrderedWith(U:! type) { | |
fn Compare[self: Self](u: U) -> Ordering; | |
} | |
fn StringLess(s1: String, s2: String) -> bool { | |
return s1 < s2; | |
// => s1.(OrderedWith(String).Compare)(s2) == Less | |
} | |
fn StringGreater(s1: String, s2: String) -> bool { | |
return s1 > s2; | |
// => s1.(OrderedWith(String).Compare)(s2) == Greater | |
} | |
choice Ordering { | |
Less, | |
Equivalent, | |
Greater, | |
Incomparable | |
} | |
interface OrderedWith(U:! type) { | |
fn Compare[self: Self](u: U) -> Ordering; | |
} | |
fn StringLess(s1: String, s2: String) -> bool { | |
return s1 < s2; | |
// => s1.(OrderedWith(String).Compare)(s2) == Less | |
} | |
fn StringGreater(s1: String, s2: String) -> bool { | |
return s1 > s2; | |
// => s1.(OrderedWith(String).Compare)(s2) == Greater | |
} | |
interface OrderedWith(U:! type) { | |
fn Compare[self: Self](u: U) -> Ordering; | |
default fn Less[self: Self](u: U) -> bool { | |
return self.Compare(u) == Ordering.Less; | |
} | |
default fn LessOrEquivalent[self: Self](u: U) -> bool { | |
let c: Ordering = self.Compare(u); | |
return c == Ordering.Less or c == Ordering.Equivalent; | |
} | |
default fn Greater[self: Self](u: U) -> bool { | |
return self.Compare(u) == Ordering.Greater; | |
} | |
default fn GreaterOrEquivalent[self: Self](u: U) -> bool { | |
let c: Ordering = self.Compare(u); | |
return c == Ordering.Greater or c == Ordering.Equivalent; | |
} | |
} | |
interface OrderedWith(U:! type) { | |
fn Compare[self: Self](u: U) -> Ordering; | |
default fn Less[self: Self](u: U) -> bool { | |
return self.Compare(u) == Ordering.Less; | |
} | |
default fn LessOrEquivalent[self: Self](u: U) -> bool { | |
let c: Ordering = self.Compare(u); | |
return c == Ordering.Less or c == Ordering.Equivalent; | |
} | |
default fn Greater[self: Self](u: U) -> bool { | |
return self.Compare(u) == Ordering.Greater; | |
} | |
default fn GreaterOrEquivalent[self: Self](u: U) -> bool { | |
let c: Ordering = self.Compare(u); | |
return c == Ordering.Greater or c == Ordering.Equivalent; | |
} | |
} | |
interface Printable { | |
fn Print[self: Self](); | |
} | |
class Vector(template T:! type) { ... } | |
impl forall [T:! Printable] Vector(T) as Printable { | |
fn Print[self: Self]() { | |
var first: bool = true; | |
for (elem: T in self) { | |
if (not first) { ", ".Print(); } | |
elem.Print(); | |
first = false; | |
} | |
} | |
} | |
interface As(Dest:! type) { | |
fn Convert[self: Self]() -> Dest; | |
} | |
impl String as As(Path) { | |
fn Convert[self: String]() -> Path { | |
return Path.FromString(self); | |
} | |
} | |
let config_file: Path = "/etc/myutil.cfg" as Path; | |
// => ("/etc/myutil.cfg").(As(Path).Convert)() | |
interface ImplicitAs(Dest:! type) { | |
extends As(Dest); | |
// Inherited from As(Dest): | |
// fn Convert[self: Self]() -> Dest; | |
} | |
impl String as ImplicitAs(StringView) { | |
fn Convert[self: String]() -> StringView { | |
return StringView::Make(self.Data(), self.Data() + self.Size()); | |
} | |
} | |
fn Greet(s: StringView) { Print("Hello, {0}", s); } | |
fn Main() -> i32 { | |
Greet("audience"); | |
// => Greet(("audience").(ImplicitAs(StringView).Convert)() | |
return 0; | |
} | |
impl forall [U:! type, T:! As(U)] | |
Optional(T) as As(Optional(U)); | |
impl forall [U:! type, T:! ImplicitAs(U)] | |
Optional(T) as ImplicitAs(Optional(U)); | |
impl forall [T:! type] | |
NullOpt as ImplicitAs(Optional(T)); | |
interface CommonTypeWith(U:! type) { | |
let Result:! type | |
where Self impls ImplicitAs(.Self) and | |
U impls ImplicitAs(.Self); | |
} | |
class InternedString { ... } | |
impl InternedString as CommonTypeWith(String) | |
where .Result = StringView {} | |
fn SelectString(condition: bool, s: String, i: InternedString) -> StringView { | |
// Carbon version of ... ? ... : ... in C++: | |
return if condition then s else i; | |
} | |
fn SelectLongString(s: String, i: InternedString, v: StringView) -> auto { | |
if (s.Size() > 20) { | |
return s; | |
} else if (i.Size() > 20) { | |
return i; | |
} else { | |
return v; | |
} | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point; | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
fn GenericDouble[T:! MulWith(f64)](x: T) -> auto { | |
let scale: f64 = 2.0; | |
return x * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point; | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
fn GenericDouble[T:! MulWith(f64)](x: T) -> auto { | |
let scale: f64 = 2.0; | |
return x * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
interface MulWith(U:! type) { | |
let Result:! type = Self; | |
fn Op[self: Self](rhs: U) -> Result; | |
} | |
class Point { | |
var x: f64; | |
var y: f64; | |
impl as MulWith(f64) where .Result = Point { | |
fn Op[self: Self](scale: f64) -> Point; | |
} | |
} | |
fn Double(p: Point) -> auto { | |
let scale: f64 = 2.0; | |
return p * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} | |
fn GenericDouble[T:! MulWith(f64)](x: T) -> auto { | |
let scale: f64 = 2.0; | |
return x * scale; | |
// => p.(MulWith(f64).Op)(scale) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment