00:16:01 | * | q66 quit (Quit: Quit) |
00:32:31 | Araq | argh ... that's not what I pushed :-/ |
00:34:26 | Araq | oh well ... good night |
06:08:03 | * | Guest11697 quit (Read error: Connection reset by peer) |
06:08:32 | * | Guest11697 joined #nimrod |
06:36:12 | * | Guest11697 quit (Ping timeout: 256 seconds) |
06:40:05 | * | XAMPP joined #nimrod |
06:54:51 | * | XAMPP quit (Read error: Connection reset by peer) |
06:55:18 | * | XAMPP joined #nimrod |
06:55:18 | * | XAMPP quit (Changing host) |
06:55:18 | * | XAMPP joined #nimrod |
08:30:48 | * | XAMPP quit (Read error: Connection reset by peer) |
12:23:04 | * | Boscop quit (Disconnected by services) |
12:23:06 | * | Boscop joined #nimrod |
12:46:07 | * | Amrykid2 joined #nimrod |
12:51:44 | * | XAMPP joined #nimrod |
12:57:14 | * | Araq_ joined #nimrod |
12:58:33 | * | Araq_ quit (Client Quit) |
12:58:59 | * | q66 joined #nimrod |
17:20:02 | * | gradha joined #nimrod |
17:21:20 | gradha | reading through http://cbloomrants.blogspot.com.es/2012/10/10-26-12-simple-stuff-c-should-have.html it seems nimrod completely fails the test of number 2, which is variable name hiding |
17:21:40 | * | comex quit (Quit: Coyote finally caught me) |
17:21:54 | * | comex joined #nimrod |
17:21:55 | gradha | while compilers have grown options to warn programmers about name hiding, nimrod allows it and doesn't generate any warning/hint |
17:22:58 | gradha | I successfully tested this redefining a counter var inside a loop, which made the outside variable not increment count on loop passes |
17:23:43 | reactormonk | gradha, depends, I'd expect a new scope to hide old vars |
17:24:14 | gradha | I'm not against the feature, but I certainly wish it could be turned a warning or error, this has saved me several times |
17:24:33 | reactormonk | oke |
17:24:45 | gradha | or to rephrase that, I guess I am against the feature |
17:24:52 | reactormonk | hum? |
17:25:25 | gradha | in practice I would be running with this turned as an error always, so it means I effectively don't like new scopes to hide others |
17:26:07 | * | comex quit (Client Quit) |
17:26:18 | * | comex joined #nimrod |
17:26:25 | reactormonk | go post an issue on github |
17:26:45 | gradha | true, will do |
17:34:56 | * | comex quit (Remote host closed the connection) |
17:35:31 | * | comex joined #nimrod |
17:36:45 | Araq | gradha: actually an earlier design of the symbol table used to include a warning for it |
17:37:08 | Araq | but it is a complete misfeature with templates/macros |
17:37:27 | Araq | so I decided to not do it |
17:38:11 | Araq | in fact, since parameters are readonly, this is an idiom: |
17:38:16 | Araq | proc p(a: int) = |
17:38:19 | Araq | var a = a |
17:38:21 | Araq | dec a |
17:38:47 | gradha | interesting |
17:38:59 | Araq | and I cannot remember a single bug because of it :P |
17:39:18 | Araq | this holds for other languages too |
17:39:28 | Araq | so I'm intested in examples |
17:39:32 | Araq | where it's error-prone |
17:39:40 | Araq | because for me it definitely isn't |
17:41:48 | gradha | loops are quite the obvious stuff, I've usually hid global variables, so I resorted to naming convention: g as prefix for all globals |
17:41:56 | gradha | yeah, yeah, globals are bad, etc |
17:42:15 | reactormonk | depends on the usage |
17:47:21 | Araq | I often use a g for globals too ;-) |
17:47:43 | Araq | but as I said, I often use hiding to *prevent* bugs: |
17:48:03 | Araq | var a = a+3 # ok, can't accidentically use the old 'a' in the scope |
17:48:26 | dom96 | hello |
17:48:29 | Araq | hi dom96 |
17:52:52 | Araq | "The entire C overload/override method only works by coincidence" |
17:53:07 | Araq | er ... the guy seems to confuse C and C++ ... |
17:54:38 | gradha | he knows, probably a typo or too lazy to write ++ |
17:55:19 | gradha | btw, for the sake of a tutorial example I believe it is more "real" to have it like http://pastebin.com/gqrS3aqW |
17:55:41 | gradha | no point in exporting the name field if the objects themselves won't be exported |
17:56:26 | Araq | but you can do: |
17:56:28 | Araq | type |
17:56:37 | Araq | PPerson* = ref TPerson |
17:56:41 | Araq | TPerson = object |
17:56:44 | Araq | a*: int |
17:56:54 | Araq | it's a feature |
17:57:03 | gradha | cool, add it to the tutorial too! |
17:57:12 | Araq | ok, now that we have 'ref object' it's not that important anymore though |
18:01:03 | Araq | btw your examples should get rid of 'of TObject' |
18:01:14 | Araq | your objects are clearly not designed for inheritance anyway |
18:01:59 | Araq | you need some 'init' procs and use 'method' etc. to make objects really inheritable |
18:02:05 | Araq | it's a bit verbose but I don't mind as I despise inheritance |
18:03:29 | gradha | even if I got rid of "of TObject" would you be able to use the inheritable pragma? |
18:04:45 | gradha | there's just a paragraph or two in the tutorial about inheritance, looks like intentional |
18:05:08 | Araq | tut2 is very terse about everything |
18:05:26 | Araq | so it's not really intentional ;-) |
18:05:49 | gradha | so if you don't specify "object of TObject" it means final and nothing can inherit that? |
18:05:55 | Araq | yes |
18:05:59 | gradha | looks scary |
18:07:16 | Araq | wild inheritance is much scarier :P |
18:07:47 | Araq | "oh lets inherit from that though the author never thought if it's safe to do that" |
18:09:26 | gradha | most people probably use inheritance as a shortcut mechanism to avoid typing tedious composition methods and want to add just one or two extra things to the class |
18:12:18 | Araq | yeah and then it won't work because you can't override 'new' :P |
18:12:37 | Araq | I'm talking about Java/C#'s 'new' syntax |
18:13:13 | Araq | inheritance is stupid, much more often you want to *patch* an existing class |
18:14:24 | gradha | right now if I wanted to patch a class in nimrod without inheritance I would create one myself, compose, and then type all the required procs to satisfy the same interface |
18:14:51 | Araq | yeah |
18:14:56 | gradha | is it possible to write a macro which would do that for you? I mean, the tedious forwarding of procs |
18:15:02 | Araq | or you write a 'delegate' macro |
18:15:10 | Araq | indeed it's possible |
18:16:07 | gradha | which reminds me I still haven't gone through the second tutorial, oh the joy of 15s attention spans... |
18:17:03 | zahary | my current plan is to call the proxy types feature {.delegator.} btw (I mean the macro responsible for the rewrite) |
18:18:49 | zahary | inheritance is certainly abused, but not using it sometimes is also a problem - for example in nimrod PSym is good example of the "sumo object" anti-pattern |
18:19:19 | zahary | … having an object with fields that are sometimes unused, sometimes mean different things, etc |
18:22:05 | Araq | actually PSym could also use a 'case' ... |
18:22:22 | Araq | inheritance would save some memory though |
18:22:42 | Araq | which is one of the reasons why I included it in nimrod actually |
18:23:36 | zahary | it's understandable why it's the way it's now. it would have been less convenient if we have to cast Sym types all the time |
18:23:54 | zahary | but the type based case statement could improve things |
18:24:19 | zahary | case x |
18:24:40 | zahary | of PModule: # x is automatically treated as PModule in the block |
18:26:40 | Araq | yeah and that's the "failure to use polymorphism" 'anti-pattern' |
18:27:07 | Araq | these anti-patterns are often more useful and less harmful than "real" patterns ... |
18:27:16 | Araq | ;-) |
18:28:18 | Araq | btw I'm implementing first class iterators |
18:28:24 | Araq | here's what the code contains: |
18:28:42 | Araq | s.kind = skLet # transform skForVar into a 'let' variable |
18:28:49 | zahary | well, yeah, but your other points about how in procedural code (swithc statements) you can more easily mix context from the calling function and context from the polymorphic objects is true sometimes |
18:29:14 | Araq | try that with inheritance :P |
18:29:43 | zahary | we've talked about it - the price is the open/closed principle, but I don't disagree in general |
18:30:20 | Araq | yeah but currently I'm talking about "class switching" at runtime |
18:30:32 | Araq | which most OO languages don't support at all |
18:31:12 | gradha | isn't that something like scary wild inheritance in the wrong hands? |
18:33:29 | Araq | but it is safe as the "new" object doesn't need additional space in memory |
18:33:51 | Araq | we could also do: |
18:34:13 | Araq | type PParam = distinct PSym {.allowFieldAccess.} |
18:34:36 | Araq | and then get some type safety back |
18:34:56 | Araq | if 'allowFieldAccess' would exist, that is ... |
18:35:34 | zahary | yeah, distinct has quite a potential - we have to implement all these goodies at some point :) |
18:39:41 | Araq | alright, so lets talk about first class iterators again |
18:42:10 | Araq | iterator count(): int = yield 1; yield 2; yield 3 |
18:42:23 | Araq | for x in count(): ... # simple ... |
18:42:48 | Araq | var x = count # produces closure environment |
18:42:58 | Araq | var y = count # produces fresh closure environment |
18:43:04 | Araq | x() # 1 |
18:43:08 | Araq | x() # 2 |
18:43:16 | Araq | y() # 1 |
18:43:36 | zahary | ok, but I think it still should be var x = count() |
18:43:57 | Araq | but that can't work |
18:44:07 | Araq | how could it? |
18:44:16 | Araq | x() # 3 |
18:44:22 | Araq | x() # what now? exception? |
18:44:34 | Araq | currently it keeps producing 3 |
18:45:08 | dom96 | Goes back to 1? |
18:45:09 | zahary | well, you should support the full iteration protocol value, hasMore, next |
18:45:28 | zahary | var x = count() # x becomes an object that has these methods |
18:45:37 | Araq | ugh |
18:45:52 | Araq | that works completely different then |
18:45:57 | Araq | I know we talked about it |
18:46:16 | Araq | but 'count' is translated to a state machine |
18:46:25 | Araq | not into some object with methods |
18:46:55 | Araq | so providing 'next', 'hasMore' etc. is not natural/simple to do |
18:47:14 | Araq | well ok, 'hasMore' is simple |
18:48:20 | zahary | I suggested other ideas too (applying the decision to turn it into a closure lazily, etc), but in a previous conversation I think we've talked about the 3 methods (when I say methods, I don't mean nimrod methods, but rather an overloaded functions for the particular generated type) |
18:50:15 | zahary | it's true that the state machine becomes a bit heavier if there is also a cached "value" field |
18:53:22 | Araq | well the problem is: I already implemented the state machine and it works nicely ;-) |
18:53:37 | zahary | but the hard part stays the same? |
18:53:48 | Araq | and since it uses new goto-like AST nodes, it really provides something new |
18:53:49 | zahary | lifting local variables to closure fields, etcv |
18:54:11 | Araq | whereas the "object way" can perhaps be entirely done with a macro |
18:54:17 | zahary | and you still have next() proc I imagine, that just returns the next value |
18:54:29 | Araq | yes |
18:54:48 | zahary | so, the questing is whether - next returns it or stores it in another field in the closure |
18:55:36 | Araq | actually that's not the interesting question ;-) |
18:56:12 | Araq | the interesting question is to how make this mechanism support light-weight tasks |
18:56:38 | zahary | what is your definition of light-weight tasks? |
18:56:48 | Araq | *that*s the question |
18:56:50 | Araq | :-) |
18:57:06 | Araq | the state machine doesn't capture the stack, alright |
18:57:29 | zahary | I like async programming so this is what yield gives you in that direction - http://taskjs.org/ |
18:58:06 | zahary | this is about non blocking code running the reactor pattern |
18:58:06 | zahary | http://en.wikipedia.org/wiki/Reactor_pattern |
18:58:25 | Araq | ah yeah, that's what I need to copy |
19:01:48 | Araq | some other minor detail: currently an iterator expression 'f' produces nkClosure(f, newEnvironment[f]()) |
19:02:07 | Araq | and it's not that obvious from the code that it does that |
19:02:45 | Araq | so we could have a built-in like 'wrap(f)' that performs environment creation more explicitely |
19:03:19 | Araq | however, doing it implicitly is consistent with: 'for x in f()' |
19:03:19 | zahary | nkClosure is something new? |
19:03:38 | Araq | not really, it's the (fn, env)-pair |
19:03:55 | Araq | but an "implementation node" |
19:04:21 | Araq | inevitably it will turn out to be useful in some macro |
19:04:45 | Araq | but I haven't thought about it |
19:04:55 | zahary | so the question is whether the user have the write var it = wrap(it)? |
19:05:04 | Araq | yes |
19:05:27 | zahary | I prefer not, but as I said there is value in discriminating the iterator symbol from a started iteration |
19:05:52 | Araq | yeah but we can have a 'wrap' that simply resets the closure's state |
19:05:55 | zahary | so var x = iter is different than var x = iter(). and foo(iter) is different than foo(iter()) |
19:06:11 | Araq | yes |
19:06:17 | Araq | but it's like that for procs already |
19:06:40 | * | ekselkiu joined #nimrod |
19:06:46 | zahary | I'm sayting this because of your example: |
19:06:47 | zahary | var x = count irc://irc.freenode.net:6667/# produces closure environment |
19:07:07 | zahary | should be var x = count(), right? |
19:07:18 | Araq | no |
19:07:28 | Araq | consider this: |
19:07:41 | zahary | but isn't var x = count "assing the count symbol to x" |
19:07:51 | Araq | for c in count() |
19:07:56 | Araq | # --> equivalent: |
19:08:00 | Araq | let x = count |
19:08:04 | Araq | for c in x() |
19:08:20 | Araq | so 'count' without () needs to create the environment |
19:08:46 | zahary | aha, I see. missed that detail. but then is this supported too? var x = count(); for c in x |
19:09:04 | Araq | no, 'x' would be single 'int' then |
19:09:06 | zahary | or you chose let, because of my inlining ideas for the future? |
19:09:25 | Araq | let or var doesn't matter here |
19:09:45 | zahary | can I iterate without a for loop? |
19:10:07 | zahary | that's really needed for the promises/yield library |
19:10:09 | Araq | yeah, I think so: |
19:10:11 | Araq | while true: |
19:10:57 | Araq | var (y, stopped) = next(x) |
19:11:01 | Araq | if stopped: break |
19:11:10 | Araq | and yes |
19:11:36 | Araq | this 'next' came to my mind just now |
19:11:56 | Araq | I had in mind some 'finished' but that wouldn't really work |
19:12:28 | zahary | I was about to suggest it as alternative to embedded value, but it's not that different |
19:13:11 | zahary | so, var x = count(); var (v, stopped) = next(x); |
19:13:17 | zahary | I think this should work |
19:16:01 | Araq | thinking about it, also this syntactical position 'for ... in CREATE_ENV' could trigger environment creation ... |
19:16:29 | Araq | the implicit environment creation causes some problems for 'const' iterators |
19:16:46 | Araq | const muhaha = [iter1, iter2, iter3] |
19:17:01 | Araq | let mu = muhaha[1] # env creation here? |
19:17:14 | zahary | no, mu is symbol at this point |
19:17:38 | Araq | hrm? |
19:17:55 | zahary | well, it's really like procs in my wordview |
19:18:08 | zahary | if it was |
19:18:08 | zahary | const muhaha = [proc1, proc2] |
19:18:20 | zahary | var mu = muhaha[1] # mu is a proc pointer |
19:19:20 | Araq | ok, so [iter1, iter2, iter3] is an array of closures |
19:19:36 | zahary | array of "iterator" procs. calling an "iterator" proc produces an Iteartor[T] object, which is a run-time closure object |
19:20:19 | zahary | let x = iter1 # iterator proc |
19:20:19 | zahary | let y = iter1() # or let y = x() # closure object |
19:22:25 | Araq | but then you have ()() where you used to have only () |
19:22:34 | zahary | like where/ |
19:22:53 | Araq | iter1()() # produces first value |
19:23:04 | Araq | that's weird IMHO |
19:23:18 | zahary | but how often I want to produce the first value like that? |
19:23:57 | zahary | and we already said that it may be next(iter1()) # if you want the alternative syntax can throw an exception in the end indeed |
19:24:21 | Araq | it's about consistency, it feels very inconsistent to the second class iterators that already exist |
19:24:41 | zahary | to clarify, I usually assign the iterator to a variable, before starting to fetch values |
19:25:02 | Araq | proc p() = |
19:25:17 | Araq | proc q() = captureSomething() |
19:25:28 | Araq | result = q # produces environment |
19:25:51 | Araq | we don't have 'q' producing a 'Closure[T]' either |
19:26:22 | Araq | well 'q' does become an (fn,env)-pair, but you know what I mean |
19:27:21 | zahary | I see, but nested proc creating is always mapped to a value. I can also claim inconsistency in the example I posted for [proc1, proc2] vs [iter1, iter2] |
19:28:45 | Araq | not really as [proc1, proc2] does produce an environment too (if the procs are .closure.) |
19:28:59 | Araq | it's just that the environment is a dummy environment |
19:29:11 | zahary | so the real criteria is whether the proc is nested(closure) or not |
19:29:28 | zahary | since top level iterators are not nested, they are more like a top level procs |
19:29:55 | Araq | no as they require an environment nevertheless |
19:30:14 | Araq | but indeed nested iterators will be the next thing to think about: |
19:30:28 | zahary | can iterators be nested in a proc too btw? |
19:30:38 | Araq | soon they will ;-) |
19:31:23 | Araq | proc p: (iterator: int) = |
19:31:36 | Araq | var a: array[0..4, int] |
19:31:46 | Araq | result = iterator = |
19:31:51 | zahary | they have an environment, but this is the environment they create whey you call them - they are top-level factory procs - I woudn't compare them to closures (I would compare a nested iterator to a closure) |
19:31:53 | Araq | for x in a: yield x |
19:32:45 | Araq | in the implementation the iterator gets a closure that has an upval to a closure that contains 'a' |
19:33:01 | zahary | and nested iterator will be a "closure" that is a factory for an iteration |
19:33:15 | * | Trix[a]r_za is now known as Trixar_za |
19:33:51 | Araq | speaking of which, do we need a tyIter? currently an iterator has the type tyProc but that's wrong |
19:34:08 | Araq | as you mustn't pass an iterator where a proc is required |
19:34:24 | zahary | well, it could help (flag could be enough tho) |
19:34:30 | * | Trixar_za is now known as Trix[a]r_za |
19:34:55 | Araq | however I'm thinking about merging tyIter == tyProc + closure calling convention |
19:35:09 | Araq | but it's not entirely correct |
19:35:13 | zahary | calling compatibility is a good thing |
19:35:34 | Araq | as tyIter has a hidden 'state: int' field that needs to be at offset 0 |
19:35:48 | Araq | consider this: |
19:35:55 | zahary | so what, that's offset 0 in the closure env |
19:36:00 | Araq | yes |
19:36:11 | Araq | but 'next' touches it |
19:36:21 | Araq | so 'next' needs a tyIter |
19:36:28 | Araq | a tyProc + closure doesn't cut it |
19:36:55 | zahary | I would go for a strongly typed next most of the time |
19:37:51 | Araq | in fact, the signature of 'next' is complex, it requires argument list forwarding I think |
19:37:53 | zahary | ah, I think I got what you mean |
19:39:00 | zahary | well, if next returns multiple values this is just reflected in the closure type - it's not compatible indeed with the "same" closure type if you don't go the exceptions route |
19:39:07 | Araq | we can also allow 'yield' in a proc and blur the distinction between proc and iterator even further |
19:39:55 | Araq | exceptions like Python's StopIteration is silly considering the 'state: int' implemenation |
19:40:16 | Araq | instead I map a "state == -1" to "has stopped" |
19:40:32 | Araq | much more efficient |
19:40:59 | Araq | in the 'for' loop this 'state' field is accessed to see if the loop should break |
19:42:36 | zahary | further complicating the closure calling scheme to accomodate possible yields sounds a bit too much for my hi performance preferences |
19:43:57 | Araq | true but blurring the line between proc and iterator seems preferable for tasking |
19:44:01 | zahary | iterators may be compatible with closures that return [T, bool] tuples |
19:46:04 | Araq | well "complicating to accomodate" means "adding a single 'int' field to every closure" |
19:46:28 | Araq | we could even make it a 'byte' though often that wouldn't gain anything due to alignment |
19:48:22 | zahary | ok, doesn't sound that bad indeed |
19:49:16 | zahary | can I use a closure in iterator context? how would I have written the closure? |
19:49:48 | zahary | or it's just possible to use iterator in a closure context? it throws an exception if it's past the end? |
19:49:55 | Araq | I'm not sure ;-) |
19:50:39 | Araq | throwing an exception if past the end is easy to implement |
19:50:51 | Araq | but then it's also easy to explictly write the 'raise' |
19:50:56 | Araq | currently it's a nop |
19:51:12 | Araq | so the example would yield 1,2, 3,3,3 ... |
19:51:33 | Araq | because the 'result' is in the closure and stays 3 |
19:52:05 | zahary | the closure that is usable as iterator may have some kind of stop statements (or reuse break for that purpose) |
19:52:34 | zahary | you always call it to the end, but if it issues a stop statement, this will break the iteration |
19:54:06 | zahary | proc closure = |
19:54:07 | zahary | … |
19:54:07 | zahary | if x: |
19:54:07 | zahary | stop # nothing happens here, just the stop bit is raised, execution continues |
19:54:07 | zahary | result = y # this is the normal returned value |
19:54:38 | Araq | 'stop' is called 'return' ;-) |
19:55:03 | Araq | or 'yield', depending on what you mean |
19:55:08 | zahary | no, return produces a normal value; or you mean return without a value? |
19:55:38 | Araq | well your 'closure' has the type void, so a simple 'yield' is fine, right? |
19:55:47 | zahary | we are talking about a regular closure here that someone is calling like an iterator |
19:55:47 | zahary | var (v, stopped) = next(closure) |
19:56:04 | Araq | I'm still in "task" thinking |
19:56:08 | zahary | the regular closure doesn't have yield in it, it's a normal function |
19:56:33 | zahary | but don't you follow what I'm explaining? |
19:56:47 | Araq | no ... :-) |
19:56:55 | zahary | well, try harder :P |
19:57:10 | Araq | I'm not sure whether you are already explaining some great idea |
19:57:18 | Araq | or still trying to come up with a use case :P |
19:57:38 | zahary | can I use a closure in iterator context? how would I have written the closure? |
19:57:38 | zahary | or it's just possible to use iterator in a closure context? it throws an exception if it's past the end? |
19:57:50 | zahary | I asked this questions, when you suggested the unification |
19:58:08 | zahary | what I'm explaining is how the first one can be handled: "how would I have written the closure?" |
19:59:16 | Araq | well ... I can't follow: your 'closure' proc doesn't use a closure nor does it use a 'yield' |
19:59:17 | zahary | the use case is another story - there are certainly some performance implications of the duff device vs regularly compiled procs |
19:59:32 | Araq | so why should it be passable to 'next'? |
20:00:04 | zahary | well, you you have unification then every closure is passable to next and every iterator is callable as closure |
20:00:15 | Araq | ok, so it's |
20:00:16 | zahary | post procs never end - you can call them forever with next |
20:00:22 | Araq | proc closure {.closure.} = ... |
20:00:23 | zahary | most procs |
20:00:35 | Araq | fine, a dummy closure then |
20:00:43 | zahary | but some may end with the special "stop/break" statement |
20:02:16 | * | Araq needs the use case :P |
20:02:42 | zahary | use cases are certainly isomorphic - you can achieve any goal in both styles |
20:03:01 | Araq | well I'll finish what I have and push |
20:03:16 | Araq | hopefully it's stable enough to play with it |
20:03:48 | Araq | whatever you have in mind seems very simple to implement |
20:04:15 | zahary | you suggested the unification actually :) I'm just enumerating solutions |
20:05:04 | Araq | well I suggested the unification because it's almost the same implementation :-) |
20:05:38 | Araq | I dunno yet how useful it would be |
20:06:13 | Araq | I feel it's quite useful for tasking |
20:06:22 | Araq | but the details still escape me :P |
20:08:18 | Araq | btw 'state' is only necessary because the program counter is hidden from us (in C/LLVM) ... |
20:08:33 | zahary | I know |
20:08:59 | Araq | alright |
20:40:08 | gradha | hehe, trying {.raises.} in a template, I wonder if that makes sense |
20:41:00 | Araq | compiler should prevent it :P |
20:41:32 | Araq | though hrm it could be useful for documentation purposes |
20:42:06 | Araq | we could allow it but the compiler wouldn't check it (how could it?) |
20:43:25 | gradha | yes, I was thinking of documentation (rewriting todo example with templates) |
20:44:56 | Araq | what should we do with EAssertion btw? special case it? |
20:46:59 | gradha | I would, but could you then inherit from it to bypass compiler checks? seems really evil |
20:47:29 | Araq | seems like a feature :P |
20:47:48 | Araq | you can already 'cast' it away to bypass the checking |
20:48:01 | gradha | no worries then |
20:48:43 | Araq | we could even introduce a magic base class for that: EUnchecked |
20:49:31 | Araq | but I'd prefer a hack that doesn't require a compiler change |
20:49:34 | gradha | can I then in user code define my own EUnchecked class and have it treated the same? |
20:49:42 | Araq | no |
20:50:45 | Araq | stuff in 'system' is not that easily hijackable |
20:52:09 | gradha | is it because of {.compilerproc.}? |
20:52:32 | Araq | yeah but that is not enough either |
20:52:43 | Araq | it needs to be in system and 'compilerproc' |
20:54:56 | Araq | you can do: type EUnchecked = object of system.EUnchecked |
20:55:21 | Araq | though why you would want to escapes me |
20:56:17 | Araq | on the other hand ... if it can raise an EAssertion, it can raise an EAssertion; why hide that fact? |
20:57:08 | Araq | the stdlib often uses 'assert' to check against usage errors |
20:57:33 | Araq | so if a client module uses it incorrectly, it may assert |
20:58:28 | Araq | it disappears in 'release' mode but the semantics are defined by the 'debug' mode ... |
20:58:33 | gradha | originally I thought of different codepaths for release/debug versions, but actually you could have the same problem with other assertions |
20:58:44 | gradha | maybe raises should accept optional elements? |
20:59:04 | Araq | debug mode defines the semantics, release skips lots of checks for optimization |
20:59:04 | gradha | {.raises: [EInvalidSomething, EAssertion?, EDivisionByZero].} |
21:01:07 | Araq | I know EOverflow isn't listed but EOverflow et. al. would only be noise |
21:01:23 | Araq | you could argue the same for EAssertion ... hm |
21:04:12 | Araq | any opinions? |
21:06:40 | gradha | being completely explicit seems a PITA |
21:07:32 | gradha | maybe a group of exceptions should be ignored by default unless raised by user code. Now, define user code... |
21:08:21 | zahary | assert is special for me because it doesn't exist in release builds - I care for any exception that may unwind the stack in a release build |
21:09:16 | Araq | actually doAssert always checks and raises |
21:09:37 | Araq | so I guess 'assert' should simply hide the fact to the compiler |
21:10:07 | Araq | we can't reasonably make it type dependent |
21:10:46 | zahary | yes, seems to be the way to go |
21:11:04 | zahary | we need explicit tag overriding for other purposes as we've discussed before |
21:11:34 | Araq | yeah but as I said, currently you can cast or even type convert it away |
21:12:05 | Araq | and getting the logic right was already time consuming :P |
21:15:31 | Araq | however some user-defined merge/consume would be nice |
21:15:41 | Araq | lock/unlock pairs come to mind |
21:18:51 | Araq | but then it can't gurantee that locks are always acquired in some certain order |
21:19:31 | Araq | so this means lock/unlock needs to be special cased in the compiler, right? |
21:20:35 | zahary | how does the analysis work? |
21:21:09 | Araq | it computes the transitive closure of all tags from the static call graph |
21:21:33 | Araq | dynamic binding requires nannying the compiler |
21:21:43 | zahary | I meant the locking analysis in particular |
21:22:39 | Araq | well it's not implemented, but whenever a lock is added to the list of locks it would check that the specified order allows it |
21:23:09 | gradha | I'm trying to use except as a statement but I'm failing. This works http://pastebin.com/mYUk7B5n but the following doesn't http://pastebin.com/uTZtxAVc |
21:23:40 | zahary | ah, yeah, I imagined how it will work |
21:24:11 | Araq | not sure it's correct |
21:24:21 | Araq | but I think it is |
21:24:26 | zahary | so, what's problem with user defined merge when it comes to locks? |
21:24:44 | zahary | you mean if the user cheats, he can shoot himself in the foot? |
21:25:05 | Araq | no ... in fact 'merge' can work |
21:25:15 | Araq | 'consume' can't obviously |
21:25:36 | zahary | yeah, that's what I meant |
21:27:14 | Araq | nice. we should implement that. syntax? |
21:27:33 | zahary | about merging or about the lock order specification/ |
21:27:54 | Araq | the lock order can be implicit in the merge operation |
21:28:43 | zahary | in my book, merging is done with a proc that works on the effect type, but we are discussing something more built-in here |
21:28:53 | Araq | proc merge(effects: seq[FLock], newEffect: FLock) {.compileTime.} |
21:29:16 | zahary | lock order is application specific for me - you can detect changes in the lock order if you want to not requires explicit specification |
21:29:43 | zahary | if you don't want to require ... |
21:29:53 | Araq | but 'effects' would really be a list of symbols in the body |
21:31:05 | zahary | this signature looks ok, what's the problem with it again? |
21:31:23 | zahary | newEffect may be a return value |
21:31:54 | Araq | I dunno |
21:32:06 | Araq | I think it should be 'var seq' instead |
21:32:16 | Araq | so it can implement 'consume' too ;-) |
21:32:45 | Araq | there is no problem with the signature, I'm thinking loud |
21:33:10 | zahary | what is consume exactly? it's the case where I say "you know, this function doesn't allocate memory, even tho I'm pushing back elements to this sequence" |
21:33:30 | Araq | yeah well it undoes an effect |
21:33:39 | zahary | if that's consume, then it's explicit point in the code where I'm adding the consume declaration |
21:33:40 | Araq | like 'dealloc' or 'releaseLock' |
21:33:46 | zahary | merge is more global - it's always used |
21:34:14 | zahary | so, consume just have to explicitly set a value for the effect - it will use some kind of constructor |
21:34:28 | Araq | sounds like a TR macro then |
21:34:42 | Araq | you want to perform it against some pattern |
21:36:01 | zahary | proc mySeqFiller(x: var seq) = {. AllocatesMemory = None .} |
21:36:01 | zahary | x.add(1); |
21:36:26 | zahary | that's what I mean- the compiler will see x.add and decide that we are allocating memory, but we know better |
21:37:35 | Araq | meh this black- and whitelisting with lots of override mechanisms feels wrong |
21:37:39 | zahary | the example is pseudo-syntax |
21:38:00 | Araq | sure, obviously |
21:38:03 | zahary | but looks what's going on - it's not that there is something special about seq.add |
21:38:35 | zahary | the special bit here is that we have a contract that the sequence must have enough reserved memory (yeah, seq is not a good example) |
21:38:52 | zahary | so we are encoding exactly this specific contract - it's hard to match it with TR |
21:39:18 | Araq | that's true |
21:42:59 | zahary | pattern matching is useful when I extend an existing library with my own effects - for example I may want to define "breaks my sandbox" effect when deciding wether to accept a plugin from the user in source form |
21:43:36 | zahary | it such scenario, I'll want to spray some effects of the functions in the stdlib |
21:43:56 | Araq | yeah, I want the creaping featurism to stop |
21:44:36 | Araq | 'raises' and 'tags' is a nice feature, so is 'distinct' but these things can be enhanced endlessly |
21:44:48 | Araq | *improved |
21:44:59 | Araq | and it's starting to bother me |
21:45:32 | zahary | well, we just discussing possibilities - I wouldn't put this stuff any near top priority |
21:45:51 | Araq | good :-) |
21:46:20 | zahary | as usual, what's important is to not make the feature somehow incompatible with such future additions |
21:48:35 | Araq | the danger is tiny as we can always use yet-another-new-pragma ... |
21:49:18 | Araq | 'tags' is flawed? np, lets introduce 'annotations' |
21:54:56 | Araq | here you go :D |
21:56:23 | zahary | I'm currently entrenched in getting caas to work with my vim plugin |
21:56:33 | Araq | cool |
21:56:46 | Araq | note how 'invoke(count0)' subtly requires the compiler to know count0's body |
21:57:02 | zahary | what's that? |
21:57:07 | Araq | which is yet another thing to consider for implicit forwarding |
21:57:16 | Araq | tests/run/titer8.nim |
21:59:18 | Araq | oh and .closure iterators are not compile-time evaluable but that should be easy to fix |
21:59:53 | Araq | for now 'closure' is explicitly required for first class iterators but I'm not sure this should stay |
22:00:12 | Araq | my initial plan was that any iterator that's not 'inline' is a first class iterator |
22:00:24 | zahary | why is it hard to choose inlining vs closure automatically btw? |
22:00:35 | Araq | it's not |
22:00:41 | Araq | but the semantics differ |
22:00:53 | zahary | how so? |
22:01:17 | Araq | inline works better with 'try' for instance |
22:01:56 | Araq | you can't pass an inline iterator around like you can a first class iterator |
22:02:14 | zahary | I see - so you are wondering wether to allow closure to be inlined and keep non-closure as "iterator with exceptions" |
22:03:12 | Araq | I wonder what 'iterator' without any explicit calling convention should default to |
22:03:35 | Araq | no matter what we choose we'll piss off somebody :-) |
22:03:57 | Araq | for the LINQ crowd we want 'closure' be the default |
22:04:14 | Araq | for the guys who care about efficiency 'inline' is a better default I think |
22:05:46 | zahary | I'll take a look at some point how it works exactly - I still want to implement inlining in the case of: |
22:05:46 | zahary | filter(stream: iterator, f: proc) |
22:07:32 | Araq | inlining+escape analysis would really be sweet yeah |
22:13:19 | zahary | btw, is there a reason why options, globalOptions and the cmdLine are stored in each rod file? wouldn't they be the same for all files? |
22:13:58 | Araq | yes but the point is to trigger a recompilation should they change |
22:14:17 | Araq | and we have no shared/global project wide rod file |
22:14:29 | zahary | yes, that's what I was about to suggest |
22:14:57 | Araq | would help for generic instantiations |
22:15:12 | Araq | but my fear was that it quickly would grow too big |
22:15:27 | Araq | making the other rod files superfluous |
22:16:52 | Araq | also the initial plan was that the cache works per module, so if you have: |
22:16:54 | * | ekselkiu quit (Ping timeout: 260 seconds) |
22:17:07 | Araq | projectA -> moduleB |
22:17:13 | Araq | projectB -> moduleB |
22:17:35 | zahary | module here is something like "package", "library", etc? |
22:17:44 | Araq | that moduleB can be cached regardless of whether project A or B is compiled |
22:17:58 | Araq | no it's a real nimrod module |
22:18:05 | zahary | aha, I see |
22:18:52 | Araq | in fact ... it works that way now :-) |
22:19:02 | Araq | the tests depend on this behaviour |
22:19:44 | Araq | the projects need to be in the same directory for this to work |
22:19:45 | zahary | I use a scheme where my nimcache is different for debug/release - it's inconvenient to trash your cache often |
22:20:06 | Araq | yeah good point |
22:27:52 | Araq | btw using a proper binary file for rod files is fine with me if we gain a decent viewer for them at the same time |
22:28:29 | Araq | it's already too hard to debug them so the ascii that's left doesn't buy us anything |
22:28:59 | zahary | this is a smart way to write serializaion code: |
22:28:59 | zahary | http://www.boost.org/doc/libs/1_52_0/libs/serialization/doc/index.html |
22:29:22 | zahary | you can have a single function that is used to save, load and display the archive |
22:29:53 | Araq | yeah well we need on demand loading |
22:30:11 | Araq | I looked at LLVM's bitcode implemenation |
22:30:24 | Araq | but I considered it too hard to implement :P |
22:31:24 | zahary | on demand loading may be a bit more tricky, but it's not that hard - especially if you make the index and the data different files |
22:31:39 | Araq | now that's brilliant :D |
22:31:49 | Araq | never occured to me to do that |
22:32:03 | zahary | :) |
22:33:10 | Araq | we'll see if a general binary format can match rod's tight packing :P |
22:33:33 | Araq | on the other hand, 7z shows a decent compression rate for rodfiles ... |
22:33:53 | Araq | I have to sleep now, good night |
22:34:01 | zahary | good night |
22:34:11 | gradha | bye |
22:39:38 | * | gradha quit (Quit: gradha) |
23:54:36 | * | q66 quit (Quit: Quit) |