Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

distinguish ccstring (const char*) from cmstring (char*) #524

Open
timotheecour opened this issue Jan 13, 2021 · 0 comments
Open

distinguish ccstring (const char*) from cmstring (char*) #524

timotheecour opened this issue Jan 13, 2021 · 0 comments
Labels

Comments

@timotheecour
Copy link
Owner

timotheecour commented Jan 13, 2021

proposal

distinguish 2 kinds of null terminated strings, mapping to char* and const char *, eg:

type ccstring = ptr char # maps to const char*, `c` stands for const
type cmstring = ptr char # maps to char*, `m` stands for mutable

(currently, cmstring is the same as cstring on c backend but on js backend, ccstring would be a better fit to map js' string since js strings are immutable)

this will improve type safety in a number of places, in particular around FFI and ROM data (Example 1), and avoid subverting the type system (Example 2)

bikeshedding

better names welcome

implementation

this implementation works: nim-lang#3720 (comment)
and it's generic (not just for const char* but also const T* or even const T)

type ConstCharPtr* = ptr CppConst[char] # maps to const char*

example 1

would avoid this classic SIGBUS problem when writing to ROM:
nim-lang#8463 (issue still unfixed)

see nim-lang#8463 (comment)

var s1 = "abc".cstring
s1[0] = 'x' # SIGBUS

under this proposal, we have:

var s1 = "abc".cstring # give a warning (ultimately an error)
var s2 = "abc".cmstring # CT error
var s3 = "abc".ccstring # ok
s3[0] = 'x' # CT error

example 2

in example below, var s = s is needed so that s[0] = 'x' compiles, however it's a hack, we shouldn't be able to subvert the type system without using a cast;

  • either proc main(s: cstring) = s[0] = 'x'should compile without addingvar s = s`
  • or var s = s should be illegal (instead let s = s)
  • or s[0] = 'x' should be illegal
proc main(s: cstring) =
  var s = s
  s[0] = 'x'

var s = "abc"
var s2 = s.cstring
main(s2)
doAssert s == "xbc"

under this proposal, you'd have:

proc main(s: cmstring) =
  # var s = s # now not needed but would still work with it uncommented
  s[0] = 'x'

var s = "abc"
var s2 = s.cmstring
main(s2)
doAssert s == "xbc"

rationale

  • why introduce cmstring instead of keeping cstring?
    to avoid breaking code and make code transisioning to cmstring, ccstring easier (forward and backward compatible)
    eg, in js, string maps closest to ccstring, not cmstring, but cstring is already also mapping to js string
    there are other reasons which i can explain.

TODO

specify what conversions, operations are legal for ccstring and cmstring

note

in D, there's 3 notions for mutability of runtime data: mutable(the default), const, and immutable (I'm not considering CT notions of enum and static).
The missing part in the nim picture would be immutable here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant