Last active
March 24, 2024 23:58
-
-
Save honewatson/583135c1b191119a3b3be3fdbfe8607b to your computer and use it in GitHub Desktop.
Nim Concepts Example - Concepts are Generics
This file contains 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
import strutils | |
type | |
Dispatch = enum | |
Reveal | |
IKind = enum | |
Human, NonHuman | |
ObIkind = ref object of RootObj | |
kind*: IKind | |
Person = object of ObIkind | |
# Note Person has attribute name of type string | |
name*: string | |
Robot = object of ObIkind | |
# Note Robot has attribute name of type int | |
name*: int | |
Place = object of ObIkind | |
# Note Place has no attribute name but an attribute `description` of type string | |
description*: string | |
# Data concept | |
Data = concept x | |
# `x` is anything that has a `toString` procedure | |
toString(x) | |
# `x` must have kind of IKind | |
x.kind is IKind | |
# We can use a generic proc as a starting point to satisfy `Data` concept proc `toString` | |
proc toString*[T](data: T): string = "$# is a $#" % [$data.name, $data.kind] | |
# We can provide a specific `toString` proc for place which does not have a property of `name` | |
proc toString*(place: Place): string = "$# is a $#" % [place.description, $place.kind] | |
var | |
d1 = Person(kind: Human, name: "Jim") | |
d2 = Place(kind: NonHuman, description: "Hill") | |
d3 = Robot(kind: NonHuman, name: 738191) | |
# Here we create a proc actions which has takes concept of type Data as one of the parameters | |
# The concept of type Data is essentially a kind of restricted generic | |
# This should work for both the C and JS Backends | |
proc actions*(dispatch: Dispatch, data: Data): string = | |
case dispatch: | |
of Reveal: | |
toString(data) | |
echo actions(Reveal, d1) | |
# Jim is a Human | |
echo actions(Reveal, d2) | |
# Hill is a NonHuman | |
echo actions(Reveal, d3) | |
# 738191 is a NonHuman |
This file contains 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
import sequtils | |
type | |
Items = concept s | |
for value in s: | |
value.name is string | |
Base = object of RootObj | |
id*: int | |
Place = object of Base | |
name*: string | |
description*: string | |
Person = object of Base | |
name*: string | |
var place: ref Place = new(Place) | |
place.id = 1 | |
place.name = "One Tree hill" | |
place.description = "A Hill" | |
var places: seq[ref Place] = @[place] | |
var person: ref Person = new(Person) | |
person.id = 2 | |
person.name = "Billy" | |
var persons: seq[ref Person] = @[person] | |
proc getNames(a: Items): seq[string] = | |
result = a.mapIt(it.name) | |
proc getNames[T,X](a: T, b: X): seq[string] = | |
result = concat(getNames(a), getNames(b)) | |
echo getNames(persons, places) |
This file contains 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
import strutils | |
import templates | |
type | |
HasName* = concept x | |
$x.name is string | |
HasSubTitle* = concept x | |
$x.subTitle is string | |
HasSummary* = concept x | |
x is HasName | |
x is HasSubTitle | |
Sellable* = concept x | |
x.price is float | |
Header* = concept x | |
x is HasName | |
# must have header proc implemented | |
header(x) | |
#Blog is HasName, HasSubTitle, HasSummary, Header | |
Blog* = object | |
name*: string | |
subTitle*: string | |
#Product is HasName, Sellable, Header | |
Product* = object | |
name*: string | |
price*: float | |
#Robot is HasName, Header | |
Robot* = object | |
name*: int | |
proc showName*(hasName: HasName): string = $hasName.name | |
proc showSubTitle*(hasSubTitle: HasSubTitle): string = $hasSubTitle.subTitle | |
proc discount*(sellable: Sellable, discountPercentage: float): string = | |
"$" & $(sellable.price - (sellable.price * discountPercentage)) | |
proc summary*(hasSummary: HasSummary, titleH: string, subTitleH: string): string = tmpli html """ | |
<$titleH>$(hasSummary.name)</$titleH> | |
<$subTitleH>$(hasSummary.subTitle)</$subTitleH> | |
""" | |
# Private Base method equivalent | |
proc header[T](ob: T): string = """<h1>$#</h1>""" % [$ob.name] | |
# Private Method override for Robot | |
proc header(robot: Robot): string = """Model: $#""" % [$robot.name] | |
# doHeader could be use as the public api for header outside of the module | |
proc doHeader*(h: Header): string = header(h) | |
var blog: Blog = Blog(name: "Jim", subTitle: "Jim is funny") | |
var product: Product = Product(name: "Wheel", price:21.95) | |
echo blog.showName() # Jim | |
echo product.showName() # Wheel | |
echo Robot(name: 1234).showName() # 1234 | |
echo product.discount(0.1) # $19.755 | |
echo blog.showSubTitle() # Jim is funny | |
echo blog.summary("h1", "h2") # <h1>Jim</h1><h2>Jim is funny</h2> | |
echo blog.doHeader() #<h1>Jim</h1> | |
echo product.doHeader() #<h1>Wheel</h1> | |
echo Robot(name: 41251).doHeader() #Model: 41251 | |
echo "Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Concepts work in the JS backend.