Nim icon indicating copy to clipboard operation
Nim copied to clipboard

typetraits: implements `value in type`

Open alaviss opened this issue 5 years ago • 12 comments

This is useful for safe runtime type conversion, especially in range-heavy code.

Example:

type
  AllowedPort = range[1024..65535]

stdout.write("Please enter a port [1024-65535]: ")
stdout.flushFile()
let port = stdin.readLine().parseInt()

if port in AllowedPort:
  setupServer(AllowedPort(port))
else:
  stderr.write("Invalid port number")

alaviss avatar Aug 22 '20 06:08 alaviss

Unrelated CI failures.

alaviss avatar Aug 22 '20 13:08 alaviss

it would be ok to have flow typing for that . e.g. making usage of port as AllowedPort an error in the other branch: is this something that the z3-based tool can do ?

alehander92 avatar Aug 24 '20 11:08 alehander92

That'd be a good idea. I don't know how to use drnim though, so probably this can be added by someone with the knowledge after this PR.

alaviss avatar Aug 25 '20 03:08 alaviss

To be honest I don't think it a good idea to mix types and runtime values this way. IMO, constants are much better for your use case:

const AllowedPort = 1024..65535

stdout.write("Please enter a port [1024-65535]: ")
stdout.flushFile()
let port = stdin.readLine().parseInt()

if port in AllowedPort:
  setupServer(AllowedPort(port))
else:
  stderr.write("Invalid port number")

Possibly you can come up with more convincing example.

cooldome avatar Aug 25 '20 11:08 cooldome

An use case that I have is for parsers (yes, I'm aware of times.parse, this is just an example):

import times, strscans, typetraits

func parseDate(s: string): DateTime =
  var y, m, d: int
  if scanf(s, "$i-$i-$i", y, m, d):
    if m notin Month:
      raise newException(ValueError, $m & " is not a valid month")
    if d notin MonthdayRange or d == 0:
      raise newException(ValueError, $d & " is not a valid day of the month")
    result = initDateTime(d, Month(m), y, 0, 0, 0)
  else:
    raise newException(ValueError, "No valid date found")

Note that slices are not a replacement for range types. If a value is of a range type, it means that the value is guaranteed to be within the range, thus we can forward it without having to perform any checks. The main issue is that the stdlib don't provide any (ergonomic) way to perform the first check. This PR is meant to solve that.

Note that range type is just one possible use case. Other use cases include conversion between enum and int (useful when you store the enum in a database, for example), safe conversions from/to unsigned types, etc.

alaviss avatar Aug 26 '20 16:08 alaviss

@cooldome We can already do array[SomeEnum, T]; it makes sense if you think of enums as a set of their valid entries. But then you could also say it makes sense to do a in uint8 ...

Clyybber avatar Aug 27 '20 16:08 Clyybber

Opened #15232 as an alternative where the separation between types and values is more pronounced.

alaviss avatar Aug 27 '20 17:08 alaviss

Agree, last example is convincing. #15232 is more appealing

cooldome avatar Aug 28 '20 12:08 cooldome

This pull request has been automatically marked as stale because it has not had recent activity. If you think it is still a valid PR, please rebase it on the latest devel; otherwise it will be closed. Thank you for your contributions.

stale[bot] avatar Aug 28 '21 14:08 stale[bot]

Rebased

This PR can use some additional polish now that there are facilities for dealing with holey enums. However I want to know whether upstream would like this solution before investing more time into it.

alaviss avatar Sep 09 '21 00:09 alaviss

I'm actually surprised that this isn't already implemented.

Note that slices are not a replacement for range types. If a value is of a range type, it means that the value is guaranteed to be within the range, thus we can forward it without having to perform any checks. The main issue is that the stdlib don't provide any (ergonomic) way to perform the first check. This PR is meant to solve that.

This is especially true now that Defects are a thing (and it's always been possible to turn range checks off anyway).

Varriount avatar Sep 18 '21 21:09 Varriount

This pull request has been automatically marked as stale because it has not had recent activity. If you think it is still a valid PR, please rebase it on the latest devel; otherwise it will be closed. Thank you for your contributions.

stale[bot] avatar Sep 20 '22 18:09 stale[bot]