Re: Weird Behaviour

2020-02-25 Thread sigmapie8
Okay. Thanks!


Re: Weird Behaviour

2020-02-25 Thread demotomohiro
According to Nim manual: 
[https://nim-lang.org/docs/manual.html#syntax-precedence](https://nim-lang.org/docs/manual.html#syntax-precedence)

> Whether an operator is used a prefix operator is also affected by preceding 
> whitespace (this parsing change was introduced with version 0.13.0):
> 
> echo $foo
> 
> # is parsed as
> 
> echo($foo)

See how Nim parse your code: 


import macros

dumpTree:
  var x = number.len-2
  var y = number.len - 2
  var z = number.len- 2
  var a = number.len -2


Run

Output: 


StmtList
  VarSection
IdentDefs
  Ident "x"
  Empty
  Infix
Ident "-"
DotExpr
  Ident "number"
  Ident "len"
IntLit 2
  VarSection
IdentDefs
  Ident "y"
  Empty
  Infix
Ident "-"
DotExpr
  Ident "number"
  Ident "len"
IntLit 2
  VarSection
IdentDefs
  Ident "z"
  Empty
  Infix
Ident "-"
DotExpr
  Ident "number"
  Ident "len"
IntLit 2
  VarSection
IdentDefs
  Ident "a"
  Empty
  Command
DotExpr
  Ident "number"
  Ident "len"
Prefix
  Ident "-"
  IntLit 2


Run


Re: Weird Behaviour

2020-02-25 Thread cumulonimbus
> var a = number.len -2 #throws invalid Indentation error

That's because it is equivalent to `number.len(-2)` and/or `len(number, -2)` ; 
 followed by something that looks like a negative number is a 
negative number (and not a "subtract" operation).


Re: Weird Behaviour

2020-02-25 Thread Divy
Make sure you are not having any extra whitespace at the end of lines. If not, 
then check for indentations and replace them with spaces.

If done correctly, your program should work fine.


Weird Behaviour

2020-02-25 Thread sigmapie8
`proc check_number(number: string): bool = var x = number.len-2 #works var y = 
number.len - 2 #works var z = number.len- 2 #works var a = number.len -2 
#throws invalid Indentation error echo x, y, z, a return true echo 
check_number("1234") `

Run


Re: Weird Behaviour

2020-02-25 Thread enthus1ast
Please format your question properly.


Re: Weird behaviour with generic type

2019-07-14 Thread Araq
> What do you think of this solution?

I think it's a good solution.


Re: Weird behaviour with generic type

2019-07-13 Thread thenjip
I think it is fine since `TestType`'s members are private.

So, constructing a `TestType` from another module would require a call to 
`newTestType` anyway.


Re: Weird behaviour with generic type

2019-07-13 Thread vitreo12
Thank you all very much for the welcome and for all the help! I know see where 
the problem is, and I hope that, in the future, an easier syntax would work.

In any case, I went with the following solution, using a generic type at the 
type level and specializing only in the procs' interface: 


type
AbstractType  = int or string

#Fully generic type, but constrained in the procs interface.
TestType*[T, Y] = object
a : T
b : Y

proc newTestType[T : AbstractType, Y : AbstractType](a : T, b : Y) : 
TestType[T, Y] =
return TestType[T, Y](a : a, b : b)

proc print_test_type(t : TestType) =
echo t.a
echo t.b

let
t1 = newTestType(1, 2)
t2 = newTestType("string", "here")
t3 = newTestType(10, "mixed")

echo typedesc(t1)
print_test_type(t1)

echo typedesc(t2)
print_test_type(t2)

echo typedesc(t3)
print_test_type(t3)


Run

What do you think of this solution? The only problem here is that, to construct 
a 


 TestType 

Run

one should always use the 


 newTestType 

Run

proc in order to have the correct 


 AbstractType 

Run

behaviour.


Re: Weird behaviour with generic type

2019-07-13 Thread mratsim
Welcome to Nim.

You are actually touching an advanced part of the Nim type system, the `bind 
once` versus `bind many` part.

**bind once vs bind many**

Let's go through that with an example.


proc foo1(x, y: SomeInteger) =
  echo "Ran foo"

proc foo2(x: SomeInteger, y: SomeInteger) =
  echo "Ran foo"

proc bar[T, U: SomeInteger](x: T, y: U) =
  echo "Ran bar"

proc baz(x, y: distinct SomeInteger) =
  echo "Ran bar"

let a = int32 10
let b = int64 20

block: # fails
  foo1(a, b)

block: # fails
  foo2(a, b)

block: # works
  bar(a, b)

block: # works
  baz(a, b)


Run

In the first case `foo1`, from the signature it is intuitive that `x` and `y` 
should be of the same type.

The second case `foo2` is equivalent to `foo1`, for generic instantiation, once 
`SomeInteger` has been inferred from the first parameter, it is applied 
verywhere else. It is called `bind once`. The main benefit is that both 
definition are interchangeable, and it seems to be a good default.

There are 2 ways to ask the compiler to not bind once.

Option 1 via indirection: in the `bar` function, `x` of type `T` which is 
instantiated to int32, and `y` of type `U` which is instantiated to int64. The 
`[T, U: SomeInteger]` declaration only restrict T and U to be of SomeInteger 
but never instantiates `SomeInteger` so it's not bind to any concrete type like 
in the 2 previous examples.

Option 2 via explecitly asking `bind many` behaviour: in the `baz` function, 
the `distinct` keyword tells the compiler to lock the inference of 
`SomeInteger` to the type of `x`.

**The tricky part 1: distinct solution**

Hopefully the examples are simple enough and you managed to follow me until 
here. The key part to remember is that `distinct` tells the compiler to not 
`bind once`.

You might think, oh I just need to use distinct for my types then.


type
AbstractType = int or string
TestType*[T, Y : distinct AbstractType] = object


Run

Unfortunately, `distinct` has a completely different meaning in a type section.

**``distinct`` types**

Distinct types are well covered in the manual. It allows you to create units 
(for example physics units like Meter and Mile or currency like Dollar and 
Euro) and prevent you from mixing them at the type system level.

Example 


type
  Dollar = distinct int
  Euro = distinct int

# Let's borrow procedures from the base ``int`` type
proc `+`(x, y: Dollar): Dollar {.borrow.}
proc `+`(x, y: Euro): Euro {.borrow.}

# And overload the print to add the unit
proc `$`(x: Dollar): string =
  $int(x) & " dollars"

proc `$`(x: Euro): string =
  $int(x) & " euro"

let a = 10.Dollar
let b = 3.Dollar

let c = 5.Euro
let d = 1.Euro


echo a+b # Prints 13 dollars
echo c+d # Prints 6 euros

# Compile-time error "Type mismatch"
# echo a+c


Run

**The tricky part 2: indirection solution**

Since `distinct` doesn't work in a type section. You might think, well I can 
use the `bar` solution, bind `T` and `U` to different types.


type
AbstractType = int or string
TestType*[T: AbstractType; Y: AbstractType] = object
a : T
b : Y

proc newTestType[T, Y: AbstractType](a: T, b: Y) : TestType[T, Y] =
return TestType[T, Y](a : a, b : b)

proc print_test_type(t : TestType) =
echo t.a
echo t.b

let
t1 = newTestType(1, 2)
t2 = newTestType("string", "here")
t3 = newTestType(10, "mixed")

echo typedesc(t1)
print_test_type(t1)

echo typedesc(t2)
print_test_type(t2)

echo typedesc(t3)
print_test_type(t3)


Run

Well unfortunately it doesn't work, within a type section, all the generic T, Y 
types are `bind once`.

**The solution**

@thenjip nailed it, you need to shake the typesystem a bit until you "bind many 
indirections" directly at the type section level instead of the proc level:


type
AbstractType = int or string
TestType*[T : distinct AbstractType | AbstractType; Y : distinct 
AbstractType | AbstractType] = object
a : T
b : Y

proc newTestType[T, Y](a: T, b: Y) : TestType[T, Y] =
return TestType[T, Y](a : a, b : b)

proc print_test_type(t : TestType) =
echo t.a
echo t.b

let
t1 = newTestType(1, 2)
t2 = newTestType("string", "here")
t3 = newTestType(10, "mixed")

echo typedesc(t1)
print_test_type(t1)

echo typedesc(t2)
print_test_type(t2)

echo typedesc(t3)
print_test_type(t3)


Run

**Language design**

More for future improvement of the language, I think the `distinct` keyword to 
create unit types and the 

Re: Weird behaviour with generic type

2019-07-13 Thread Sixte
> the generic type parameters of newTestType are not distinct

They are unified at the type level in `TestType`. The (inferred) type is still 
`int or string` . Within `newTestType` , terms become available and obviously, 
type resolution happens at the term level. If this is intended or not might to 
be seen. 


Re: Weird behaviour with generic type

2019-07-13 Thread gemath
It's actually enough to change just one of the type constraints to make it work:


type
  TestType*[T :  AbstractType; Y : distinct AbstractType | AbstractType] = 
object
a : T
b : Y


Run

That's nice, but the fact that the signature of `newTestType` _doesn 't_ have 
to be changed shows that either there's still something really wrong with Nim's 
type resolution or that it works in a way which so runs counter my intuition 
that it's not for me: the generic type parameters of `newTestType` are not 
`distinct`, hence `AbstractType` is bind once, so why does 


t3 = newTestType(10, "mixed")

Run

even compile?


Re: Weird behaviour with generic type

2019-07-13 Thread Sixte
The compiler unifies `T` and `Y`, as long as it finds the same root type, 
`AbstractType` here. If you write down `AbstractType` again , e.g. using 
`AbstractType2`, then assigning with `Y`, the program should compile. 


Re: Weird behaviour with generic type

2019-07-13 Thread thenjip
Hello,

Redefining `TestType` this way allows reusing `AbstractType`, but I find it a 
little repetitive: 


type
  TestType*[T : distinct AbstractType | AbstractType; Y : distinct 
AbstractType | AbstractType] = object
a : T
b : Y


Run

Also, welcome to Nim, @vitreo12 !


Re: Weird behaviour with generic type

2019-07-13 Thread Stefan_Salewski
> coming from Julia.

Have missed that statement earlier this morning.

So I wonder if you really intent what you are doing?

For your TestType, you are not defining one single type, but four distinct 
different types.

So maybe what you want is sum types, called object variants in Nim?

For your compile problem, my guess is that for


TestType*[T : AbstractType, Y : AbstractType]


Run

the compiler assumes that T and Y are identical, but you want then not 
identical, so the explicit "or types" compiles.


Weird behaviour with generic type

2019-07-12 Thread vitreo12
Hello everyone! I am a new Nim user (and, I have to say, I am pretty excited 
about this language!) coming from Julia. I was tesing some of Nim's 
capabilities when coming to generic types and procs, when I ran into this code 
not compiling:


type
AbstractType = int or string
TestType*[T : AbstractType, Y : AbstractType] = object
a : T
b : Y

proc newTestType[T : AbstractType, Y : AbstractType](a : T, b : Y) : 
TestType[T, Y] =
return TestType[T, Y](a : a, b : b)

proc print_test_type(t : TestType) =
echo t.a
echo t.b

let
t1 = newTestType(1, 2)
t2 = newTestType("string", "here")
t3 = newTestType(10, "mixed")

echo typedesc(t1)
print_test_type(t1)

echo typedesc(t2)
print_test_type(t2)

echo typedesc(t3)
print_test_type(t3)


Run

The compiler error is this:


/home/francesco/Sources/nim/GenericTypes.nim(44, 21) template/generic 
instantiation of `newTestType` from here
/home/francesco/Sources/nim/GenericTypes.nim(35, 20) Error: cannot 
instantiate TestType
got: 
but expected: 


Run

On the other hand, if I substitute 


TestType*[T : AbstractType, Y : AbstractType]

Run

with 


TestType*[T : AbstractType, Y : int or string]

Run

, the code correctly compiles and executes, resulting in the expected result:


[system.int, system.int]
1
2
TestType[system.string, system.string]
string
here
TestType[system.int, system.string]
10
mixed


Run

Does anyone know why this is the case? 


Re: Understanding staticRead's weird behaviour

2018-01-18 Thread dom96
> 3 is a very bad idea, we did this for os.getConfigDir() which people then 
> used in a const section producing a binary that only works for the user who 
> compiled the program.

People? Who?

But in any case, with great power comes great responsibility. People that use 
Nim should know what `const` does. We shouldn't baby them into thinking it's 
just like a 'let'.


Re: Understanding staticRead's weird behaviour

2018-01-15 Thread c0ntribut0r
Oh, thank you all. Didn't know that readFile requires ffi...  Nim looks so 
easy but the deeper you dive the more complex it is.


Re: Understanding staticRead's weird behaviour

2017-12-20 Thread jangko
Dom96's answer no.1 is correct

> 1\. Maybe --force flag will affect this?

How can this be?, if Nim compiler detect that your .nim(on disk) not modified, 
and there is already .c/.o for the .nim in /nimcache, Nim compiler will skip 
codegen for the .c/.o file(if the dependencies/imports also not changed). Using 
staticRead(x) indeed change .nim file(in memory) if you change/update the 'x', 
but the compiler will not know about this(the compiler hash the file on disk, 
not the AST in memory).

That's why, it looks cached somehow. Perhaps you can request a new feature for 
Nim compiler to hash the 'x' too as a dependency.

No.3 Compile time FFI

if I am not mistaken, araq has a branch of Nim implementing compile time FFI, 
but then abandoned/postponed because it would be a nightmare for maintainer to 
deal with upcoming issues related to compile time FFI while the Nim compiler 
itself already had many issues. But I believe, in the future we can revive this 
idea. It will be cool although a bit nasty.


Re: Understanding staticRead's weird behaviour

2017-12-19 Thread Araq
3 is a very bad idea, we did this for os.getConfigDir() which people then used 
in a `const` section producing a binary that only works for the user who 
compiled the program.


Re: Understanding staticRead's weird behaviour

2017-12-14 Thread dom96
No idea about `1`. Maybe `--force` flag will affect this?

For `2`, your path is `app/version.txt` which suggests that it reads relative 
to your module. That makes sense to me. It's how `import` works.

For `3`, Nim can distinguish. Nim cannot perform FFI at compile-time though, 
and `readFile` requires it. We could implement `readFile` for the Nim 
compile-time VM, and I would prefer to do this to be honest. Having a different 
API for compile-time vs. run-time is an additional burden on the programmer.


Understanding staticRead's weird behaviour

2017-12-13 Thread c0ntribut0r
Hello nim lovers! Another portion of dumb questions from nim newbie 

1) Consider this project structure: 


app.nimble
app/
   - version.txt  # contains "0.1.1-3"
   - utils.nim


utils.nim contains getVersion helper which just reads from file: 


proc getVersion*(versionFile:string): seq[string] =
  staticRead(versionFile).split('-')  # static is required because I need 
this value at compile time


app.nimble: 


const
  versionFile = "app/version.txt"
# ...
task version, "Get version":
  echo "Proc call: " & $(getVersion(versionFile))
  echo "Inline call: " & $(staticRead(versionFile).split('-'))


Now here is the magic: 


> nimble version
  Executing task version in .../app.nimble
Proc call: @[0.1]  <-- WTF?!
Inline call: @[0.1.1, 3]


Okay, it looks like calling staticRead is cached somehow when using a proc 
(cause I had "0.1" some time ago). But why, and how to avoid it?

2) My versionFile must be defined **relative to `utils.nim` location** because 
that's where staticRead resides. If I move utils somewhere else, I would need 
to change versionFile's path which is absolutely terrible!

3) Also, just curious why we have to use staticRead at all? Looks like const 
already marks expressions as compile-time: 


const
  constEval = contains("abc", 'b') # computed at compile time, no need to 
use staticContains or smth
  data = readFile("somefile")  # <-- OOPS! doesn't work at compile time
  data = staticRead("somefile")  # <-- will work


Cannot nim distinguish between compile/runtime and call appropriate read 
function accordingly?