Re: Access procedure arguments from a macro when the procedure is called
@moigagoo Just be prepared, there might be some cases wher it is not that great after all. @LeuGim Basically what you are saying was what I meant with "Strangely, on my computer it did work. The compiler did not complain that value was not declared, but you were missing a len call to the parameter". But maybe it did need different words to be understood.
Re: NimYAML 0.7.0 released
NimYAML 0.8.0 is now available. Its focus was on making it more capable of being used for configuration files: * You can now set default values of object fields with `setDefaultValue`. * You can now mark object fields as transient with `markAsTransient` so that they are not serialized or expected in YAML input. * You can now ignore input keys with `ignoreInputKey`. This makes it easier to parse YAML input that contains data which is not of interest. Moreover, timestamps can now be parsed into `Time` values. However, this is only usable with most recent Nim devel version, since timezones are broken in 0.15.2.
Re: netwatch 1.0.0 - network monitor written in nim
@federico3: Trying to! :) I'm doing Linux first and unfortunately it's only when I get some free time. Help & PRs are welcome! The idea (from @endragor) is to rip out most of the low-level interface/network stuff that's in netwatch and use a psutil library instead. As an aside, Nim makes it _really_ nice to port the psutil Python code. The original library has shared Python code that calls platform-specific Python code that _then_ calls platform-specific C code. Nim doesn't need any of that extra C layer! I'm curious to see the LOC comparison after it's done. Not sure I'll get there thought b/c the author moves fast ;)
Re: netwatch 1.0.0 - network monitor written in nim
@JohnS: are you developing this? [https://github.com/johnscillieri/psutil-nim](https://github.com/johnscillieri/psutil-nim)
Re: Access procedure arguments from a macro when the procedure is called
@LeuGim Wow! Well, this is just amazing, thanks a lot for the tip! This is another case of Nim being awesome. I literally wrote the first sample as a throw-away-this-just-cannot-work-this-easily piece, and here it is, working perfectly well with just a pair of back ticks added.
Re: Access procedure arguments from a macro when the procedure is called
> it's more readable than using `setterProc.params[2][0]` You don't have to use `setterProc.params[2][0]` with your first approach (with `quote do`). Just `value` works - identifier will be resolved in the procedure being transformed, not in macro. Oppositely, to use the macro's symbol, you have to quote it with backticks. So what you had to change in your first example is to add backticks around `limit` (like in _Krux02_'s example), using `value` as is (just with `.len` appended).
Re: Access procedure arguments from a macro when the procedure is called
@Krux02 Thanks for the hint! I've already gone with the solution advised by @Araq though: import macros type ValidationError* = object of Exception template validateLength(limit: Natural) {.dirty.} = if len(value) > limit: raise newException(ValidationError, "The value is too long.") macro maxLength*(limit: Natural, setterProc: untyped): untyped = setterProc.body.insert(0, getAst(validateLength(limit))) result = setterProc I think it's more readable than using `setterProc.params[2][0]`, because these indices don't really tell anything to the code reader. So it may be a good thing I couldn't make it work the `quote` way :) Still, I wonder if using dirty templates in conjunction with `getAst` is the easiest way to emulate decorator behavior. I have a sense there must be a better way (not that this way is bad).
Re: Access procedure arguments from a macro when the procedure is called
Strangely, on my computer it did work. The compiler did not complain that value was not declared, but you were missing a `len` call to the parameter. By the way, you can also extract the exact identifier that is used in the setter, and therefore make shure that it is defined. macro maxLength*(limit: Natural, setterProc: untyped): untyped = let paramIdent = setterProc.params[2][0] let lengthValidation = quote do:# This is the part I can't figure out. if len(`paramIdent`) > `limit`: # Obviously, this doesn't work since: value is undeclared, raise newException(RangeError, "Too long") # and even if I extract the variable from ``setterProc``, its value is unknown setterProc.body.insert(0, lengthValidation) result = setterProc
Re: Fun with deduplicate
There is currently another point that confuses me: I tested with an initial array increased in size by factor 10: var x: array[1, int] Compiled with -d:release and default -O3 for gcc gcc takes 28 seconds to generate the binary and binary size is 650k. And with -Os or -O2 results are similar. Well 10k ints global should result in 80k BSS section when int size is 8 byte. But what may go on? This is for gcc 5.4 @Krux: I have to think about your comment some more still. But sorting may be indeed a problem I guess, when array elements are objects, we have to provide a cmp() proc to sort, and that cmp() proc has to compare all the fields of the object, and is called often. So that should be not very fast. And of course deduplicate operation should prevent the order in the seq and keep always the first candidate.
Re: Fun with deduplicate
As far as I know, there are three ways to deduplicate the elements of a list, and all of them can be implemented by modifying the argument or returning a new seq. You introduced the method that uses the set, but your implementation destroys the order of elements in a seq, I think that is not necessary. The third alternative is, to sort the collection, and then deduplicate _O(n log n)_. This is clearly faster than _O(n²)_, but destroys definitively the order. The advantage compared to the hashing implementation is, that it can be implemented without any allocation.
Re: Access procedure arguments from a macro when the procedure is called
`{.dirty.}` \- makes a template not to create a new scope, what is declared in it is created in the calling site.
Fun with deduplicate
I wonder if sequtils.deduplicate() should be renamed to deduplicated() as it returns a seq like sorted()? And maybe it should be noted that it is O(n^2), which is fine for small collections, but not so nice for large ones. And maybe we should add a O(n) deduplicate to stdlib -- sets modul is really fast as shown below. import sets import random, times import sequtils # deduplicate # O(n) proc uniqCopy[T](s: openArray[T]): seq[T] = let h = s.toOrderedSet newSeq(result, h.len) # can we avoid the unnecessary initialization? var i = 0 # is there no items with index for sets? for el in h: result[i] = el inc(i) # O(n) proc uniq[T](s: var seq[T]) = let h = s.toOrderedSet var i = 0 for el in h: s[i] = el inc(i) s.setLen(h.len) # O(n^2) proc xdeduplicate[T](s: var seq[T]) = var i, j: int while i < s.len: s[j] = s[i] var k = j while k > 0: dec k if s[k] == s[j]: dec(j) break inc(j) inc(i) s.setlen(j) var a = @[1, 3, 1, 2, 2, 5, 2] var b = a echo a.uniqCopy a.xdeduplicate b.uniq echo a echo b var t: float # cpuTime() var x: array[1000, int] for el in mitems(x): el = random(1000) var z = @x t = cpuTime() z = z.deduplicate echo "sequtils.dedublicate: ", cpuTime() - t z = @x t = cpuTime() z.xdeduplicate echo "inplace dedublicate: ", cpuTime() - t z = @x t = cpuTime() z = z.uniqCopy echo "uniqCopy: ", cpuTime() - t z = @x t = cpuTime() z.uniq echo "uniq: ", cpuTime() - t # nim c -d:release t.nim # Output # @[1, 3, 2, 5] # @[1, 3, 2, 5] # @[1, 3, 2, 5] # sequtils.dedublicate: 0.0001411 # inplace dedublicate: 0.0001329 # uniqCopy: 3.099e-05 # uniq: 2.711e-05
Re: Access procedure arguments from a macro when the procedure is called
Thanks for the quick response! > dirty template+getAst (the preferred way to construct ASTs these days). Could you please point me to sample code where this technique is used? I'm pretty bad at using `quote`, but `getAst` is a totally unknown thing to me, and the docs don't say much. Also, what do you mean by using a dirty template? Namely, what makes a template dirty?
Re: Access procedure arguments from a macro when the procedure is called
Your solution is just fine once you replace `quote do:` by a dirty template+getAst (the preferred way to construct ASTs these days).
Re: WINAPI Select Folder
`nimble install dialogs` import dialogs let dir = chooseDir(nil, r"C:\start\here") echo dir, " has been picked"
Access procedure arguments from a macro when the procedure is called
Hi! I need a way to validate the value during attribute assignment for an object. Using macros as pragmas sounds like a good idea, and the syntax would be sane and clear: {.this: self.} type Person* = ref object of RootObj name: string proc name*(self: Person): string = name proc `name=`*(self: var Person, value: string) {.maxLength: 100.} = name = value proc newPerson*(name: string, age: int = 0): Person = new result result.name = name The `maxLength` macro would look something like this: macro maxLength*(limit: Natural, setterProc: untyped): untyped = let lengthValidation = quote do:# This is the part I can't figure out. if value > limit: # Obviously, this doesn't work since: value is undeclared, raise newException(ValidationError, "Too long") # and even if I extract the variable from ``setterProc``, its value is unknown setterProc.body.insert(0, lengthValidation) result = setterProc I can't figure out how to extract the runtime value of the `value` argument. Maybe my approach is totally wrong. If you have a better suggestion, please advise—I'm a novice and am very keen to learn from pros. I come from the Python background, so I'm viewing macro in this example sort of like a decorator. I know they're very much different, but I don't know a better alternative to decorators or can't find a better programming pattern for the task. Again, any advice is appreciated.
WINAPI Select Folder
This question is relative to the ms windows api. Found SHBrowseForFolder function in the oldwinapi module to build a dialog to select a folder. Needed that since GetOpenFileName only selects files. That works, but requires selection to always begin at the very topmost master root. To specify the selection root in SHBrowseForFolder requires an ITEMIDLIST for that root. This seems to be some kind of generalized internal filesystem path. How do I convert an ordinary file path string (e.g. C:\Moo\Gai\Folly) into such an ITEMIDLIST? The function ParseDisplayName might do that, but I cannot find it in the oldwinapi module? Or is there some old-style winapi for a gui to select a folder?? Thanks