Often I'll have surrounding context that I use to define something, that has very little relevance outside of that something. For instance:
let placeholder = "first $delim second $delim third".split("$delim",2)
let first = placeholder[0]
let second = placeholder[1]
let third = placeholder[2]
I will want to use first, second and third elsewhere in my program, but placeholder only exists to create them, and it claims the name "placeholder" so the next time I do something like this, I have to use "placeholder2" or something, and just manually avoid name conflicts.
It's tempting to say the solution is to return a tuple, but even that requires a dummy name
proc stillaplaceholder(): tuple[str,str,str] =
const placeholder = staticRead("somefile").split("$delim",2)
return (placeholder[0],placeholder[1],placeholder[2])
let (first,second,third) = stillaplaceholder()
And often times I want to define a procedure, which isn't exactly the same as returning a procedure.
var select = prepare("SELECT info FROM thingy WHERE id = ?1")
var insert = prepare("INSERT INTO thingy DEFAULT VALUES")
proc createThingy(id: int64): something =
result = select.gofind(id)
if not result:
insert.inject()
result = last_row_id_thing()
Yeah, sqlite is great, I know. But I don't want to pollute my namespace with "select" and "insert", and it seems silly to make a separate module for every table in the database that acts like this. But I can't put it in a block, otherwise createThingy will go out of scope! I thought about using a template...
template createcreateThingy(name: untyped, select: string, insert: string) =
var a = prepare(select)
var b = prepare(insert)
proc `name`(id: int64): something =
...
but then I end up with this ridiculous bit of code:
createcreateThingy(createThingy,"SELECT info FROM thingy WHERE id = ?1","INSERT INTO thingy DEFAULT VALUES")
I'm really not trying to automate creation of the code inside the procedure. I'm just trying to hide the "select" and "insert" variables. Sure I could prepare them every time the function is called, or make some sort of a cache to look up previously prepared statements, but it's nicer to just use a surrounding context, and have nim just know which variables are which.
Is there an elegant solution to this? Or am I just being too picky, and using stuff like placeholder2 is a perfectly good idea?
Would a block expression do what you want?
import strutils
let (first,second,third) = (block:
const placeholder = "first $delim second $delim third".split("$delim",2)
(placeholder[0],placeholder[1],placeholder[2]))
Not really, because you still can't define procedures that way. It is neat that you can define unnamed blocks though, instead of a dummy name procedure. I think what I'm looking for is the {.global.} keyword, actually:
proc something(): foo =
var thing {.global.} = expensive_initialization()
return thing.use_cheaply()
I'd say that it is a bad practice to use vague names. Other than that, why can't you use var instead of let and reuse the variables?.
Your example is very confusing. But i'm sure it can be accomplished with the aid of templates/macros. Would be useful if you coded an imaginary syntax that manages to do what you have in mind, and then we could think how to translate that into a template.