proc foobar(f:Foo not nil) =
discard
let f = Foo() # nilable ref
let b: Foo not nil = f # Error, can't prove 'f' is not nil
if f != nil:
let b: Foo not nil = f # can assign non-nil vars to 'f'
foobar(f) # or can pass 'f' directly type
Foo = ref object
Bar = object
val: Foo not nil
let
f = Bar() # Error, 'val' must be set
proc foobar(f: Foo not nil): Foo not nil =
return nil # Error, can't return nil
foobar(nil) # Error, can't pass nil
> At best this dangling pointer will look at garbage and cause a crash or undefined behavior. At worst, it will look at other, actively-used memory and cause a security vulnerability. static:
# define a compile-time list first
var names = newSeq[string]()
# add some values (at compile-time)
names.add("foo")
names.add("bar")
# define the compiler vars as run-time const
const runtimeNames = names
# define some run-time variables
var name1 = "foo"
var name2 = "blah"
# check runtime variables against const variable
if runtimeNames.contains(name1): echo "Has Foo!"
if runtimeNames.contains(name2): echo "Has Blah!"
Sorry about the rather winded (and bad example) replys :| But thanks for the conversation, it reminded me of this and now I have some cleaning up of my own code to get too. Cheers! var eventNames {.compileTime.} = newSeq[string]()
proc defineEvent(name:static[string]) =
static:
eventNames.add(name)
macro checkDefined(name): stmt =
# begin new statement
result = newStmtList().add quote do:
echo "Checking for '", `name`, "'"
# loop over every known event name and
# build a run-time 'if' check for each one.
for n in eventNames:
result.add quote do:
if `n` == `name`:
echo "Found it!"
# add some events to compile-time list
defineEvent("foo")
defineEvent("bar")
# define some runtime values
let eventName1 = "foo"
let eventName2 = "blah"
# check runtime values againts compile-time list
checkDefined(eventName1)
checkDefined(eventName2)
# output:
# Checking for 'foo'
# Found it!
# Checking for 'blah'
Note: This will inject a bunch of 'if' statements for each call to 'checkDefined', which might bloat your code.. it's probably better to make a macro which defines a proc, then just call that to check run-time values.. but I left those kinds of details out of this illustration for the sake of simplicity. # using the pragma here, but we could use a 'static' block instead
var cycles {.compileTime.}: int
# ---
proc doSomething =
static:
# invoked once at compile-time (at this definition)
cycles += 1
proc doSomethingGeneric[T] =
static:
# invoked once at compile-time (per unique generic call)
cycles += 1
macro doSomethingAtCompileTime(n): stmt =
# invoked at compile-time (per call)
let ncycles = int n.intVal
cycles += ncycles
# ---
doSomething() # this call doesn't effect 'cycles', it's declaration does (+0)
doSomething() # ditto (just here to prove a point) (+0)
doSomethingGeneric[int]() # this call effects 'cycles' (+1)..
doSomethingGeneric[int]() # ..but only once (+0)
doSomethingGeneric[float]() # this call also effects 'cycles' (+1)
doSomethingAtCompileTime(5) # this call effects 'cycles' (+5)
doSomethingAtCompileTime(12) # ditto (+12)
static:
echo cycles # prints '20'
I'm not sure this helps solve anything in NimES, but this can be really useful for meta-programming in general. For instance I'm using it to make an event system which generates efficient dispatch lists based on the types/procs defined. It's designed for game logic, to both minimize boiler-plate and dynamic dispatch. Ie, invocation it's type-specific and usually does not use function pointers per-instance, so smaller 'events' can be inlined. Plus, instances are generic (decoupled from object inheritance), and often don't require any header data. That combination should, in theory (still WIP), give devs a 'universal' way to model a broad range of game objects from heavy single-instance types to lightweight projectiles and particles. Here's an example for a little clarity: # note: 'impl', 'spawn', and 'invoke' are macros
type
Foo = object
val: int
Bar = object
val: string
impl Foo:
proc update = echo "Foo: ", me.val
proc render = echo "Rendering Foo!"
impl Bar:
proc update = echo "Bar: ", me.val
spawn Foo(val:123)
spawn Bar(val:"abc")
invoke update
invoke render
invoke blah
# ouptput:
# Foo: 123
# Bar: abc
# Rendering Foo!
# Invoke Error: No event 'blah' defined.
Perhaps that's not the best example to illustrate Nim's meta capabilities, but so far Nim is the only language I've come across that allows me to achieve this short of thing (at least, directly from user-code).
A good graphics API, even a web one, is one that provides good control over the GPU.. and to have sane standards which limit future implementation fragmentation (like shader byte-code instead of a specific shader language), and to have good debugging tools, etc.. That's what Vulkan is, regardless of how verbose it is in comparison to OpenGL.
I'm not saying you can just make Vulkan run on the web, but I'm certainly in favor of a Vulkan-subset (using SPIR-V as a shader base) becoming the successor to WebGL over one inspired by Metal and MSL.