I am experimenting with using concepts
I am trying to enforce compile time checking of ipv6
import std/[setutils,strutils]
type
V4 = array[4,int]
hexnode = concept a
a is string
a.len == 4
a.toSet < HexDigits
V6 = array[8,hexnode]
IpAddr = V4 or V6
let
home:V4 = [127,0,0,1]
hexno:hexnode = "absd"
loopback:V6 = ["2341","2341","2341","2341","2341","2341","2341","2341"]
After wrestling with it for a while, I realised that the length and hexdigits can computed at runtime. Is there a way to enforce the length and hexdigits in the type system?
I think strong types and arrays provide everything you need already. No need for fancy concepts (yet?).
type
V4 = array[4, byte]
V6 = array[8,V4]
proc print(val: V4|V6) =
echo val
proc toV4[T](val: openArray[T]): array[4, byte] =
for i,c in val:
# do more validation
result[i] = c.byte
proc toV6[T](vals: openArray[T]): array[8,V4] =
for i,val in vals:
# do more validation
result[i] = val.toV4
# normal
let home:V4 = [127,0,0,1].toV4
# even compile-time
const loopback:V6 = ["2341", "2341", "2341", "2341", "2341", "2341", "2341", "2341"].toV6
print(home)
print(loopback)
Thanks for the reply
I was trying to check for the rules at compile time (experimenting with type safety and such).
While I understand that this method will work, it is not at compile time.
I think this is what I was looking for
I take it that it's not available now.
Does RFC mean it's just a suggestion, or is it in planning / experimental ?
RFC is Request for Comment is a discussion of what could be.
In Nim types are checked at compile time, so any procs or funcs you write accepting these types will fail to compile if the array datatype or lengths don't match what is being passed to them.
Conversion from user input to this datatype for example is necessarily runtime, but again any code passing that type to procs or funcs accepting that type must pass compile time checks. If as in my example you have all the information to construct the type at compile time then you can do that as well. Nim is quite flexible.
Create a distinct string named IPv4 or whatever you want. Next, create a proc that takes in static string and outputs IPv4.
func toIpv4(str: static string): Ipv4 {.inline.} =
# Do your check here.
# As long as you use `static` types and `const`, you can do everything at compile time just fine
# Placeholder code because I don't want to write an IPv4 parser right now
const isValid = str == "127.0.0.1"
# Use `when` so that you can use the `fatal` pragma conditionally to make compile time errors
when not isValid:
{.fatal: "Invalid IPv4".}
return str.Ipv4
proc echoInetAddr(ip: Ipv4) =
echo ip.string
# OK
echoInetAddr("127.0.0.1".toIpv4)
# Error: fatal error: "Invalid IPv4"
echoInetAddr("sdfhoisdfh".toIpv4)
You're always overprotective.
func toIpv4(str: static string): static Ipv4 {.inline.} how does one inline code that requires the result to be static?
Anyway I would suggest naming the proc ipv4str so you can use ipv4str"127.0.0.1" as it reads much nicer in my view.
You're always overprotective.
I have an inherent distrust of compilers lol
Anyway I would suggest naming the proc ipv4str so you can use ipv4str"127.0.0.1" as it reads much nicer in my view.
I agree with this