Skip to content

Instantly share code, notes, and snippets.

@honewatson
Last active March 24, 2024 23:58
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save honewatson/583135c1b191119a3b3be3fdbfe8607b to your computer and use it in GitHub Desktop.
Save honewatson/583135c1b191119a3b3be3fdbfe8607b to your computer and use it in GitHub Desktop.
Nim Concepts Example - Concepts are Generics
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
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)
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!"
@honewatson
Copy link
Author

Concepts work in the JS backend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment