Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-30 Thread timothee
@Dennis my bad I should've verified the D code I posted; with tuples though we 
have:


import std.stdio:writeln;
void fun(T...)(T n)
{
static foreach (x; n)
writeln(x);
writeln("L=", T.length);
}
void main(){
import std.typecons:tuple;
fun(tuple(1,2).expand); // L=2
fun(tuple(1).expand); // L=1
fun(tuple().expand); // L=0
}


in any case, the previous answers make total sense regarding Nim's behavior. 


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread Dennis
> in D, variadic argument size will be 0 when calling fun(bar()); since bar 
> returns void isn't that a better behavior? if not what would be downsides of 
> that?

It doesn't? Aside from the wrong semi-colon in the for-loop it gives an error:

[https://run.dlang.io/is/6sfUA5](https://run.dlang.io/is/6sfUA5)

"cannot deduce function from argument types !()(void)"

It seems like weird behavior if that were the case. What would fun(1, bar(), 
1); do, give a list of 2 integers?


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread dom96
> @timothee
> 
> Why don't you write D as d? Please learn to write Nim with a capital letter. 
> This is disrespectful at least.

I seriously doubt @timothee meant it in a disrespectful way. This is a 
programming forum, not a parliamentary chambers so no need to call people out 
for such things. 


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread Lando
> fun(bar()) # n.len=1 ?? why not 0?

Because fun is a macro, not a function. A macro call is not supposed to 
"evaluate" its arguments - definitely not untyped ones - before using them. It 
takes pieces of code, transforms them into AST nodes (in this case: one node, 
hence n.len = 1) and makes a new AST node out of them. Your D example shows a 
function, which is a completely different animal.

Imagine bar had side effects. Would you really want fun(bar()) to result in 
code which does nothing (since the varargs argument would be considered 
"empty")?


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread jangko
> Maybe I'm missing some valid use case I haven't thought about?

Nim macros cannot be directly compared to D templates/generics. You can use Nim 
macros to implement DSL, such as assembler, JIT engine, shader language, etc:


macro my_asm_engine(n: varargs[untyped]): typed =
  bla bla bla


my_asm_engine:
  mov eax, ebx
  xor eax, eax
  whatever


if Nim macros choose to ignore void returning function call, it would be 
unusable to implement DSL at all. 


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread timothee
@rpowers thanks, that solves my problem! and thanks for the rationale, makes 
sense.


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread dataman
@timothee

Why don't you write D as d? Please learn to write Nim with a capital letter. 
This is disrespectful at least.


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread rpowers
Oh, right!  I guess it's testing it on untyped rather than the actual type in 
the macro. Anyways, this one is definitely working, it just tests for 
void-typed arguments:


import macros
import typetraits
import strformat

macro fun*(n: varargs[typed]): typed =
result = newNimNode(nnkStmtList, n)
var echoedCount = 0
for x in n:
if x.getTypeInst.typeKind != ntyVoid:
result.add(newCall("echo", x))
echoedCount += 1

result.add(newCall("echo", newStrLitNode($(echoedCount

proc bar() = echo "ok"

fun(1+1) # n.len=1
fun() # n.len=0
# comment this to make it work
fun(bar())



> isn't that a better behavior? if not what would be downsides of that?

No, I think automatically filtering void arguments in a macro is not a better 
or intuitive behavior. What if you remove a return type from a function and the 
compiler just silently starts ignoring it in argument lists instead of 
producing a type mismatch error? That seems like it could be an interesting 
source of bugs.

I guess what you're asking for is not SFINAE, but it feels similar -- it's a 
hack used to make template systems have some limited metaprogramming. I think 
that you'll find that sort of thing is not necessary with Nim, you can just 
write a macro that does what you want. Is there something specific that you're 
trying to do that requires the argument-ignoring approach used in D? Maybe we 
could help you come up with a good solution for it in Nim. 


Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread timothee
> bar returns nothing, how could you echo it. I see nothing to fix here, 
> especially not the involved lengths.

if nim treated a void-returning function call as being 0 arguments as in D (as 
if no argument was passed) then there would be no call to echo (ie, fun(bar()) 
would call bar() and then fun()) ; this introduces less edge cases (no need to 
consider void variables). Maybe I'm missing some valid use case I haven't 
thought about?

> I guess that D has implemented some kind of SFINAE that won't run for args 
> that cause errors?

no, it's simpler than that: as I was explaining above, in D, variadic argument 
size will be 0 when calling fun(bar()); since bar returns void

isn't that a better behavior? if not what would be downsides of that?

> it doesn't need those sorts of things, but you can certainly emulate the 
> behavior.

your code doesn't work, compiles(echo(x)) still returns true; here's a full 
modified example so you can click run:


import macros
import typetraits
import strformat

macro fun*(n: varargs[untyped]): typed =
result = newNimNode(nnkStmtList, n)
var echoedCount = 0
for x in n:
if compiles(echo(x)):
result.add(newCall("echo", x))
echoedCount += 1

result.add(newCall("echo", newStrLitNode($(echoedCount

proc bar() = echo "ok"

fun(1+1) # n.len=1
fun() # n.len=0
# comment this to make it work
fun(bar())



Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-29 Thread rpowers
I guess that D has implemented some kind of SFINAE that won't run for args that 
cause errors? Since Nim has a full macro system, it doesn't need those sorts of 
things, but you can certainly emulate the behavior. Use the proc compiles, 
which will return true if an expression compiles without errors:


macro fun*(n: varargs[untyped]): typed =
result = newNimNode(nnkStmtList, n)
var echoedCount = 0
for x in n:
if compiles(echo(x)):
result.add(newCall("echo", x))
echoedCount += 1

result.add(newCall("echo", newStrLitNode($(echoedCount

proc bar() = echo "ok"




Re: a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-28 Thread Araq
`bar` returns nothing, how could you `echo` it. I see nothing to fix here, 
especially not the involved lengths. 


a proc returning void creates 1 arg, not 0: breaking generic code

2018-03-28 Thread timothee

import macros
import typetraits
import strformat

macro fun*(n: varargs[untyped]): typed =
  result = newNimNode(nnkStmtList, n)
  for x in n:
result.add(newCall("echo", x))
  
  result.add(newCall("echo", newStrLitNode($(n.len

# void-return proc
proc bar() = echo "ok"

fun(1+1, "abc", 42) # n.len=3
fun(1+1, "abc") # n.len=2
fun(1+1) # n.len=1
fun() # n.len=0

# gives Error: type mismatch: got 
fun(bar())  # n.len=1 ?? why not 0?


in D it works correctly and doesn't break generic code: 


void fun(T...)(T n){
   static foreach(x:n)
 writeln(x);
  writeln(T.length);
}

void bar(){writeln("ok");}

fun(1+1, "abc", 42);
fun(1+1, "abc");
fun(1+1);
fun();
fun(bar());


  * is that nim choice by design or could that be fixed so that n.len = 0 in 
above code?
  * how would we work around it in my macro fun to detect whether the type of x 
is void and proceed accordingly?