@Tiberium Oh, that's wonderful! I like Was interface removed too (I'd really like to use it sometimes)?
2017-09-30 19:04:12
2017-09-30 19:31:56

Thanks for the replies!

Would other people find it useful if I made and uploaded a "pythonwith" nim package for this?

2017-10-01 07:28:36
I don't think is worth the effort for roughly 5 or 6 template lines, but i think there is already a pythonesque library in nimble. 2017-10-01 10:15:14
It could be helpful to support something like the contextmanager decorator in Python, which lets the user specify "enter" and "exit" as the code before and after yield, e.g.

iterator myfunc(name: string):
  var myfile = open(name)
  yield myfile
  myfile.close()

var myit = myfunc(filename)

with context(myit) as f:
  ...
or maybe
withcontext myit as f:
  ...

I haven't tried this, but maybe something like:

macro withcontext(args, body: untyped): untyped =
  var varValue = args[1]
  var varName = args[^1]
  ...
  template takeImpl(thisit, name, body) =
    block:
      var private {.genSym.} = thisit
      var name = private()
      try:
        body
      finally:
        private()
        assert private.finished()
  # Generate AST
  getAst(takeImpl(varValue, varName, body))

2017-10-01 16:43:21
Why not do something like:
template withFile(f: string, mode: string, statements: untyped) =
    var fileMode: FileMode
    case mode
    of "r":     fileMode = FileMode.fmRead
    of "w":     fileMode = FileMode.fmWrite
    of "a+":    fileMode = FileMode.fmReadWrite
    of "r+":    fileMode = FileMode.fmReadWriteExisting
    
    var file {.inject.} = open(f, fileMode)
    defer: file.close()
    statements
usage example:
withFile("/path/to/file", "r"):
    while not endOfFile(file):
        echo(file.readLine())
2017-10-01 17:03:24

@Arrrrrrrrr: I haven't seen a package like that, have googled this subject a few times before. Point me at it?

@Benjaminel: I'm trying to emulate the Python "with" style, which is more general-purpose than just files. I think that "using" in C# is similar, to take any given resource for a block, and then auto-close it for you at the end of that block.

@cdunn2001: I don't have any idea how to do that! For now I'm mainly interested in a python-like "with" statement; the other stuff is too advanced for me , eg to give an example of how you'd expand the one to the other. I think that's more on the level of how Dom managed to hack in async and await with just macros.

@All:

Thanks for the replies so far! So, another question

Can you update the macro so that it can work without an "as X" clause?

eg, something like this:

echo "I'm anywhere on the filesystem"

with myTempDirChange("/tmp/x"):
   echo "I am now under /tmp"

echo "I'm back to where I was before"

Which then would expand to something along these lines:

echo "I'm anywhere on the filesystem"

var private_x = myTempDirChange("/tmp/x")

try:
   echo "I am now under /tmp"
finally:
   my_exit(private_x)

echo "I'm back to where I was before"

Where myTempDirChange records the current dir, stores that in an object, then returns that object. And my_exit returns to that directory contained in that temporary object. I'm a bit hazy on exact details - whether there is still an intermediate my_enter function needed or not.

Well, basically how idiomatic Python would handle something like this behind the scenes:

print("I'm anywhere on the filesystem")

with my_temp_dir_change("/tmp"):
    print("I'm now under /tmp")

print("I'm back to the directory I was at before")

This is more of a toy example; other things might be locks, or other cases where you might normally use a "defer" statement to do some kind of tidy-up.

Another random example:

echo "sdl2 not yet initialized"

with my_init_sdl2():
   echo "SDL2 is now initialized"
   
   # Over here do your regular SDL2 logic, but don't need to worry about
   # calling sdl2.quit yourself.

echo "sdl2 was shut down"

Would like to be able to have a "with" macro that supports both forms, based on whether there is an "as" clause.

Thanks!

2017-10-05 05:33:07

Since you don't want to dive into macros and you don't need anything super-generic, I think you're better off with @Benjaminel's idea:

template withcd(newdir: string, statements: untyped) =
  let olddir = os.getCurrentDir()
  os.setCurrentDir(newdir)
  defer: os.setCurrentDir(olddir)
  statements
import os

proc hi() =
  echo "in:", os.getCurrentDir()

hi()

withcd("bar"):
  echo "It works!"
  hi()

echo "Finish it."
hi()

in:/foo
It works!
in:/foo/bar
Finish it.
in:/foo

2017-10-07 18:48:52
cdunn2001: "There's actually a lot of places I'd really like to use "withAs" in, eg to make sure that resources are closed, but without needing to add a resource-specific "defer" line." So wizzardx will need to create a template like this for every type he'll use
2017-10-07 19:23:58
<<<••12••>>>