| 00:11:55 | * | fowl joined #nimrod |
| 00:15:25 | Araq | I also have x11 crashes ... |
| 00:36:28 | * | Trix[a]r_za is now known as Trixar_za |
| 00:39:25 | NimBot | Araq/Nimrod 6ac07be Araq [+0 ±8 -0]: first steps to the expr/stmt unification |
| 01:13:22 | * | Trixar_za is now known as Trix[a]r_za |
| 01:29:30 | reactormonk | Araq, not anymore here |
| 02:43:28 | * | fowl quit (Ping timeout: 245 seconds) |
| 03:07:35 | reactormonk | Araq, nope, the codegen fails. |
| 03:12:50 | reactormonk | Araq, http://sprunge.us/SCjA |
| 03:36:32 | * | fowl joined #nimrod |
| 03:52:39 | * | OrionPK quit (Read error: Connection reset by peer) |
| 07:48:35 | NimBot | Araq/Nimrod f9522a1 Araq [+0 ±1 -0]: new js codegen: bugfixes |
| 08:12:15 | * | zahary_ joined #nimrod |
| 08:22:10 | fowl | morning all. i've been reading a lot about different component system designs and implemented an rdbms-inspired design: https://gist.github.com/fowlmouth/5487130 |
| 08:26:23 | * | Trix[a]r_za is now known as Trixar_za |
| 08:27:00 | zahary_ | I've implemented an extremely efficient such system in C++. in the end it used space directly comparable to multiple inheritance and message dispatch speeds very close to virtual function calls |
| 08:28:33 | Araq | ## nimrod bug with `-`(a,b: set[t]) --> reported? |
| 08:28:36 | zahary_ | most designs in the books and articles try to be simple to understand first and efficient second. in particular, they fail to exploit the important fact that most of the objects that will be created have share a common structure (every tank in the game is composed of the same set of components: Renderable,RigidBody,AIAgent, etc) |
| 08:28:52 | fowl | Araq: yes |
| 08:29:11 | zahary_ | to exploit this you must have a type like TypeInfo that describes the layout of the actual instances and is shared between all of the instances |
| 08:30:35 | Araq | what's the advantage of a component system? |
| 08:30:46 | fowl | zahary: right, so all the possible base components are basically a columns in a table of entities, when a new entity is created its added to any systems that can support it |
| 08:30:57 | zahary_ | the instance itself (entity) could be merely an array of the components that build it up (with their offsets specified in the TypeInfo) - in my system they were even directly constructed in a shared blob of memory |
| 08:32:10 | fowl | zahary: i plan on generating a tuple of the base components and an enum to identify them, in the same order, so entities[entity_id][CPosition] could be used to get to the position (maybe) |
| 08:32:26 | fowl | CPosition is also tied to `pos` for access in my other design so i'll keep that |
| 08:33:11 | zahary_ | well, the entity object have to be polymorphic, it's inefficient if you reserve space for every possible entity in the tuple |
| 08:33:26 | * | q66 joined #nimrod |
| 08:33:33 | zahary_ | a typical game ends up with about 250-500 component types |
| 08:35:24 | fowl | nah you just need a small set of inheritable components :) |
| 08:35:29 | Araq | zahary_: what's the advantage of a component system over MI or simply composition? |
| 08:35:31 | zahary_ | Araq, I've described this before. it solves the problem that it's impossible to define a correct inheritance tree when there are multiple ways to discriminate between objects: |
| 08:35:31 | zahary_ | renderable vs non-renderable, physical vs non-physical, user controlled, vs AI controlled |
| 08:36:46 | Araq | yeah but I can't see why composition can't work here |
| 08:37:17 | Araq | well composition may create too big objects I guess |
| 08:37:49 | zahary_ | it turns the problem around by basic everything on composition of traits. what is an enemy tank? it's renderable, it participates in path-finding, it installs sensors for vision in the spacial partitioning system, etc. each of this capabilities is represented by a separate component that can be added or removed to the type |
| 08:38:06 | zahary_ | basing everything ... |
| 08:38:13 | fowl | zahary: please critique my implementation when you get a chance :) also if need be handling the rows polymorphically is only a step away imo |
| 08:39:09 | zahary_ | fowl, I did critique it already - add a typoinfo type. make the entity a very cheap object using information from the typeinfo to support operation like "get component" |
| 08:39:57 | zahary_ | add a vtable in the type info and write helper macros for defining procs working with entities that automatically dispatch to the right component |
| 08:40:09 | fowl | ah im a bit leary of using typeinfo for runtime discernment of what components a type has |
| 08:40:30 | zahary_ | my system had a notion of multicast messages - messages that get dispatched to every component that impelements them in the entity |
| 08:41:06 | zahary_ | this proved to be very useful. for example all kind of component want to register shapes in the physics system for various purposes |
| 08:41:42 | zahary_ | you have a single multicast message like "registerPhysicalShapes" and any component can plug into it |
| 08:42:28 | zahary_ | most examples in the books use this style . Foo* f = entity.getComponent(Foo); f->DoStuff() |
| 08:43:01 | zahary_ | I find this to be bad practice as it increases physical dependencies and coupling - we preferred strongly the entity based messages |
| 08:43:38 | zahary_ | DoStuff(entity); // gets dispatched to the right component withing this entity, allows for polymorhic code just like virtual functions |
| 08:44:01 | fowl | well i do not need to fetch components, being in the system guarantees the data is available |
| 08:46:38 | zahary_ | wells, let's agree on the vocabulary here. what's an entity? this is an instance of something in the game world, right? one particular house, tank or player? so how do you get the 3D model of that particular house? |
| 08:50:48 | fowl | an entity is an index in the seq of data, you could do entity.rendr_data isa P3DModelInstance |
| 08:51:04 | fowl | er entity_data.rendr_data isa P3DModelInstance |
| 08:52:06 | zahary_ | alright, what I called entity so far is the TEntityData type in your design |
| 08:52:33 | zahary_ | mare sure that it doesn't include space for every single component in the system, but rather only for those that compose this particular instance |
| 08:53:36 | fowl | i dont think thats possible without using generic functions for everything |
| 08:55:08 | zahary_ | it's possbile. getComponent becomes: entityData->components[entityData->typeInfo->componentOffset[ComponentID]] |
| 08:56:02 | zahary_ | typeinfo is a fat object, but this is because there will be many instances having the same structure in the game - the most popular object type (a basic 3d model part of the scene) will have thousands of instances in the world) |
| 08:56:38 | zahary_ | so all of these instances are cheap, but share the same typeinfo object |
| 08:57:14 | fowl | thousands of instances, which are references to one model, with a position component and maybe some color/texture info |
| 08:58:42 | zahary_ | yes, and in you current design each one of them will be a tuple composed of 250 null pointers |
| 08:58:54 | zahary_ | ... and 3 non-null |
| 08:58:58 | fowl | you have to cast to use the offset dynamically right |
| 08:59:05 | fowl | er well i guess you'd have to cast anyways |
| 08:59:15 | zahary_ | yes |
| 08:59:48 | fowl | ok |
| 09:00:27 | fowl | could be faster by defining entity types and saving the offset info outside of the entities |
| 09:01:01 | fowl | but youd lose dynamic entity types ..hrm |
| 09:02:01 | zahary_ | there is a way to define type composed of other objects - that are regular nimrod types - no need for an entity systems. The entity system allows you to treat all objects polymorphicly |
| 09:02:40 | fowl | yea i plan on doing all this with hefty macros |
| 09:20:34 | Araq | I still don't get it ... |
| 09:20:51 | Araq | so how are your entities laid out in memory, zahary_ ? |
| 09:21:20 | zahary_ | mine system is evil. it allocates a blob of memory enough to store all components and uses placement new to construct them there |
| 09:21:34 | zahary_ | it achieves dynamically the layout that the compiler will use in multiple inheritance |
| 09:21:57 | Araq | so you can keep them in array, right? |
| 09:22:18 | zahary_ | in my system, the offset is a bytes offsets |
| 09:22:52 | Araq | yeah but *ultimately* are they kept in an array or in a list? |
| 09:23:08 | zahary_ | what I proposed to fowl here is to do something simpler, and to skip the single-allocation blob and just use seq[PComponent] and offset within this sequence |
| 09:23:42 | Araq | well I'm interested in your highly efficient way of doing it |
| 09:23:59 | zahary_ | there is no array in my system. to get a component you do entityData->componentsStorageBytes[entityData->typeInfo->componentByteOffset[ComponentID]] |
| 09:24:31 | zahary_ | during construction time of the typeinfo, the corrent aligned offsets are computed |
| 09:24:34 | zahary_ | correct |
| 09:25:31 | * | Trixar_za is now known as Trix[a]r_za |
| 09:26:13 | * | xcombelle joined #nimrod |
| 09:26:42 | Araq | well how do you iterate over all entities? |
| 09:26:49 | zahary_ | each entity looks like this struct Entity { TypeInfo* typeinfo; void* storage; | |
| 09:26:55 | zahary_ | } |
| 09:27:58 | Araq | now we're getting somewhere ... keep it low level please ;-) |
| 09:28:07 | zahary_ | iterating over all entities is something you may want to do, but this is not a concern of the entity system. in our project there were a World class that stored all the entities (also, they were stored in some spacial systems allowing you to determine visibility, raycast, etc) |
| 09:29:40 | Araq | shouldn't Entity directly contain the position btw? most entities are somewhere in the world |
| 09:30:21 | Araq | and if Entity is of a variable size, how do you store it in the "World" class? |
| 09:30:37 | zahary_ | there are things like areas and wether objects that either have non-standard positions or no position at all |
| 09:30:50 | zahary_ | so we had a separate component for the position |
| 09:31:12 | zahary_ | WorldNode - almost everything has it |
| 09:32:08 | fowl | zahary: was this an in-house project |
| 09:32:58 | zahary_ | it was an engine used for several games |
| 09:36:27 | Araq | so Entity is the tank, right? and that consists of several components? |
| 09:36:49 | zahary_ | yes, a tank would be one example |
| 09:37:21 | Araq | so where does the void* storage point to? |
| 09:37:57 | Araq | the | means it's a "struct" of variable size. right? |
| 09:38:00 | zahary_ | storage is a memory blob laid out like this: [[WorldNode][3DModel][RigidBody]...] |
| 09:38:32 | zahary_ | all the components that compose the instance in a single piece of allocated memory |
| 09:38:43 | zahary_ | no | was a typo :) |
| 09:38:53 | Araq | ah ... lol |
| 09:38:55 | zahary_ | storage; } |
| 09:39:10 | zahary_ | I meant that's the whole entity type - 2 pointers |
| 09:39:39 | Araq | and these are kept in an array in the world object? |
| 09:40:00 | zahary_ | well, you can keep them whatever way you find useful in your project |
| 09:40:14 | zahary_ | they are normal C++ types after all |
| 09:40:39 | zahary_ | in most games you want to be able to find them spatially or to just update them on each frame somehow, so they end up registered somewhere |
| 09:40:51 | Araq | yeah but come on ... somebody needs to iterate over all tanks and updates their state ;-) |
| 09:41:31 | zahary_ | in our World, they were kept in hashmap [ObjectID -> Entity*] |
| 09:41:37 | zahary_ | that was used for iteration on each frame |
| 09:43:03 | zahary_ | as you should see, this is something that depends on the game needs, not something that should be imposed on users by the entity system |
| 09:44:10 | Araq | yeah, got it |
| 09:54:05 | Araq | [[WorldNode][3DModel][RigidBody]...] # this means you keep all WorldNodes in an array, all 3dmodels in a separate array etc. right? |
| 09:54:45 | zahary_ | no, I keep all components of a single Tank close to each other |
| 09:55:11 | fowl | zahary: would entities share 3Dmodel components or are they instances that reference the model |
| 09:55:36 | zahary_ | my system also had another type of components called pinned components |
| 09:56:05 | zahary_ | these were allocated separaqtely [[WorldNode][pointer to pinned Foo][RigidBody] ...] |
| 09:56:53 | zahary_ | pinning was important issue, because it technically was possible to mutate instances at run-time by adding and removing component, but this required moving things in memory |
| 09:57:04 | zahary_ | so pinned component guaranteed that they won't be moved around |
| 09:57:41 | zahary_ | if you want to have all WorldNodes in a single array (for locality), what was possible is to use pinned components combined with free-lists for allocating them |
| 09:58:30 | Araq | there was some pdf that suggested this locality is essential but I can't find it |
| 09:58:37 | zahary_ | fowl, sharing was possible with pinned components that have refcounts |
| 09:58:52 | zahary_ | yes, I've read it |
| 09:59:06 | zahary_ | we exploited such locality in other places |
| 09:59:21 | zahary_ | for example, on each frame you have to compute the final transform matrix for each object before rendering it |
| 09:59:35 | zahary_ | many engines will store that in the WorldNode equivalent |
| 09:59:57 | fowl | what is locality ? |
| 09:59:59 | zahary_ | but it's better if you store it in a per-frame allocated memory both for memory savings and improved locality |
| 10:00:31 | Araq | fowl: basically programming with memory caches in mind |
| 10:00:33 | zahary_ | the memory savings come from the fact that you only need to compute it (and use memory for it) only for visible objects |
| 10:01:00 | fowl | ah ok |
| 10:19:36 | * | Reiser quit (Ping timeout: 245 seconds) |
| 10:23:20 | fowl | hrm i am now getting this: `Error: internal error: wrong instantiated type! |
| 10:23:21 | fowl | No stack traceback available` |
| 10:23:52 | Araq | so the typeinfo describes what components an entity consists of and at which offset to find it, right? |
| 10:25:54 | fowl | ye\ |
| 10:27:04 | * | Reisen joined #nimrod |
| 10:27:38 | zahary_ | Araq, yes. it also holds a big vtable used when messages are dispatched to components |
| 10:31:37 | Araq | why do you need this? you can easily do: fn(entity[positionOffset(entity.typeInfo)]) ? |
| 10:32:44 | Araq | you can get away with static dispatch with your scheme |
| 10:33:16 | zahary_ | because of the coolness of the multicast messages that I described and the possibility for polymorphism (one message implemented by different components in different instances) |
| 10:34:12 | fowl | i changed up TSystem a bit and now i get this weird internal error: wrong instantiated type! with no trace .. https://gist.github.com/fowlmouth/5487130#file-components2-nim-L47 |
| 10:34:44 | zahary_ | in theory, a very efficient system will be one that allows you to define various type of messages - multicast, statically dispatched, dynamically dispatched and they all will use the same syntax in the user code so it will be very easy to switch the way given message is dispatched |
| 10:34:58 | zahary_ | entity.foo should be the syntax everybody uses |
| 10:35:08 | Araq | fowl: well I'm afraid that's a tough one ... :-/ |
| 10:36:06 | fowl | Error: unhandled exception: f.sons[0].kind == tyGenericBody [EAssertionFailed] |
| 10:36:52 | fowl | heres the trace https://gist.github.com/fowlmouth/5487911 |
| 10:37:08 | fowl | you should switch koch to a nakefile (: |
| 10:44:25 | Araq | fowl: edit compiler/sigmatch.nim line 564 |
| 10:44:38 | Araq | er like 556 |
| 10:44:43 | Araq | *line |
| 10:45:08 | Araq | instead of the assert do: |
| 10:45:22 | Araq | if f.sons[0].kind != tyGenericBody: |
| 10:45:29 | Araq | debug f |
| 10:45:37 | Araq | debug a |
| 10:45:42 | Araq | assert false |
| 10:46:41 | Araq | and then you only need to find out how a tyGenericInvokation can ever be build without a tyGenericBody at position 0 ;-) |
| 10:49:11 | fowl | i was specifying the generic params explicitly |
| 10:49:20 | fowl | lol that assert false made the compiler not recompile |
| 10:53:33 | Araq | how can that be? |
| 10:54:11 | Araq | it bootstraps in debug mode so obviously f.sons[0].kind == tyGenericBody in the compiler itself everywhere |
| 10:54:56 | fowl | oh lol i didnt see the if line -_- |
| 10:55:08 | zahary_ | this often happened to me in the beginning - making some change that make the compiler unusable |
| 10:55:44 | zahary_ | https://gist.github.com/zah/5487992 it's faster to build a debug version and use that for testing usually. these are some helpers I use |
| 10:56:02 | Araq | koch boot ensures you always have a working compiler |
| 10:56:17 | zahary_ | yes, but it could be brutally slow if you do something stupid |
| 10:57:04 | fowl | er ok so the problem is this TActiveSystem*[userData] = object of PSystem i thought that was Okay |
| 11:00:01 | Araq | it is okay, the compiler has a bug obviously |
| 11:00:53 | fowl | o |
| 11:00:55 | Araq | on the other hand your userData stuff cries for a closure |
| 11:03:46 | fowl | id still need a separate type for systems that return something |
| 11:15:45 | Araq | zahary_: did you do any measures how your component engine performs against a hash based scheme? in particular I wonder how lua tables + luajit would perform for this use case |
| 11:17:19 | Araq | an entity can simply be a lua table that contains all its components and access is uniform: entity[Component] |
| 11:17:31 | zahary_ | my engine used only fixed offsets for all operations and didn't waste space as a hashtable would |
| 11:17:57 | Araq | true but you have an indirection via the typeInfo to get the offset |
| 11:20:10 | zahary_ | I guess seq[PComponent] could be more easily comparable to a hashtable, but I cared for the single memory allocation too so I didn't even consider such design |
| 11:22:54 | Araq | how's the debugging experience when all your data is in a void* btw? ;-) |
| 11:23:22 | zahary_ | visual studio allows you to write a primitive form of debugging visualizers |
| 11:24:04 | zahary_ | http://www.idigitalhouse.com/Blog/?p=83 |
| 11:24:24 | zahary_ | we used these to make it display a tree of the components |
| 11:24:35 | zahary_ | but it's essential to be able to do this indeed |
| 11:40:28 | fowl | i am trying to get around this bug by nesting the the types, its not working >_< |
| 11:58:11 | Araq | fowl: tried to make TSystem generic as well? |
| 12:13:17 | fowl | i think the problem was that i was still referring to PSystem[T] in a proc |
| 12:14:30 | Araq | aha |
| 12:14:41 | Araq | well that sounds much easier to fix in the compiler then :P |
| 12:15:04 | fowl | yes when i get this to compile ill try it again the original way to make sure |
| 12:22:41 | Araq | ugh! |
| 12:22:45 | Araq | this works ... |
| 12:22:51 | Araq | proc retInt(x: int): int = |
| 12:22:53 | Araq | result = case x |
| 12:22:55 | Araq | of 23: 3 |
| 12:22:56 | Araq | of (var yy = 1; for i in 0..1: yy *= 8; yy): 2 |
| 12:22:58 | Araq | else: 1 |
| 12:23:13 | Araq | --> the compiler happily computes yy at compile time for the case branch ... |
| 12:24:45 | Araq | oh well it reports a non-const expr correctly ... |
| 12:25:01 | Araq | quite impressive |
| 12:28:09 | fowl | Araq: ok no error now |
| 12:28:24 | Araq | fowl: report it anyway |
| 12:28:38 | fowl | i recall seeign an issue like this already |
| 12:37:39 | fowl | no thats a diff issue |
| 12:41:11 | NimBot | Araq/Nimrod 4854859 Araq [+0 ±3 -0]: proper scoping for 'if' |
| 12:41:28 | Araq | well the new (;;) stuff works now afaict |
| 12:41:31 | Araq | bbl |
| 12:44:56 | zahary_ | merge the new branch already :) |
| 12:48:58 | fowl | agreed |
| 14:15:13 | reactormonk | Araq, http://sprunge.us/SCjA |
| 14:24:31 | * | Reisen quit (Ping timeout: 264 seconds) |
| 14:29:30 | * | Reisen joined #nimrod |
| 14:54:12 | Araq | reactormonk: fixed it already |
| 15:11:40 | * | zahary_ left #nimrod (#nimrod) |
| 15:31:00 | * | xcombelle_ joined #nimrod |
| 15:33:25 | * | xcombelle quit (Ping timeout: 248 seconds) |
| 15:55:20 | reactormonk | good |
| 16:13:23 | * | Trix[a]r_za is now known as Trixar_za |
| 16:23:17 | Araq | ugh, I broke the tester? |
| 16:24:38 | Araq | oh I see ... hrm |
| 16:24:40 | Araq | ping zahary |
| 16:54:42 | * | Amrykid quit (Ping timeout: 264 seconds) |
| 16:56:32 | * | Boscop quit (Quit: Boscop) |
| 17:02:04 | * | Amrykid joined #nimrod |
| 18:29:00 | * | Boscop joined #nimrod |
| 18:44:01 | * | Trixar_za is now known as Trix[a]r_za |
| 19:02:53 | * | xcombelle_ quit (Remote host closed the connection) |
| 19:33:02 | reactormonk | Araq, what's the state of covariance? |
| 19:33:16 | reactormonk | maybe relevant http://twitter.github.io/effectivescala/#Types%20and%20Generics-Variance |
| 19:35:40 | Araq | the state is as it was before: covariance/contravariance doesn't work for value based datatypes and it doesn't really work with containers without lots of complexity and so I don't give a shit |
| 19:36:30 | Araq | and btw C# got it right before scala I think |
| 19:38:23 | reactormonk | that's possible |
| 19:57:19 | * | Trix[a]r_za quit (Ping timeout: 256 seconds) |
| 19:57:47 | * | Trix[a]r_za joined #nimrod |
| 20:16:32 | fowl | im going to start writing hideous code and posting it to the pascal and basic forums |
| 20:17:06 | fowl | IF MYVAR.ODD: |
| 20:17:23 | fowl | FOR x,y IN foo.items: |
| 20:17:23 | Araq | and accomplish what, fowl ? ;-) |
| 20:17:51 | fowl | get someone to run something hopefully |
| 20:18:12 | fowl | infect them with my fowliness |
| 20:19:46 | * | gradha joined #nimrod |
| 20:24:01 | gradha | the threads module says the different memory model improves efficiency and the channels module says the implementation is slow |
| 20:24:05 | gradha | so which one is it? |
| 20:24:52 | Araq | well both are correct |
| 20:25:02 | Araq | thread local heaps are nice for performance |
| 20:25:14 | Araq | data exchange sucks though |
| 20:25:52 | gradha | so nimrod is better for low communication parallelization? |
| 20:25:57 | Araq | if you know what you're doing you can pass 'ptr's between threads |
| 20:26:18 | Araq | and get back the efficiency |
| 20:26:47 | Araq | the missing piece is fast shared memory ... I'm working on it |
| 20:27:07 | Araq | well the design is finished in my head ... ;-) |
| 20:27:53 | gradha | I was planning on throwing idetools external execution into a thread pool and see the fireworks |
| 20:29:53 | Araq | well in fact, there also is a shared heap already ... it's not GCed though |
| 20:30:03 | Araq | the profiler uses it |
| 20:31:52 | Araq | gradha: use osproc parallel process execution instead for idetools |
| 20:32:33 | Araq | the compiler can't be threaded easily |
| 20:34:09 | gradha | I'll do this manually to report progress reports, but will take a look at execProcesses() code |
| 20:34:54 | gradha | this is the kind of API which would gain a lot through a user supplied proc |
| 20:36:50 | Araq | hmm true |
| 20:37:08 | Araq | but then you have to decide which effects the callback may have |
| 20:37:57 | fowl | what is allowed inside expr[T] |
| 20:39:29 | Araq | fowl: don't use expr[T] please for now; it will be renamed to static[T] |
| 20:40:44 | Araq | hmm effect propagation for callbacks is actually quite simple to implement ... |
| 20:41:00 | Araq | yay ... another todo list item ... |
| 20:42:45 | gradha | can you specify "you can pass any proc to this function except those generating X,Y and Z effects"? |
| 20:43:06 | Araq | that's a planned feature, currently it can't be done |
| 20:44:42 | Araq | gradha: what's the use case? |
| 20:44:53 | Araq | what effects do you want to rule out? |
| 20:44:59 | gradha | don't have any |
| 20:47:03 | gradha | in the old days you could implement functions called in interrupt contexts and you wanted them to be fast, maybe disallow IO effects and similar? |
| 20:48:00 | Araq | yeah but then you want to disallow FTime and FLua (invokes Lua scripting somewhere) too |
| 20:48:14 | Araq | so you end up with tags:[] |
| 20:49:06 | Araq | if you want to restrict effects you often really want to allow what you in fact considered valid |
| 20:49:31 | Araq | and so you whitelist the allowed effects instead of blacklist the undesired effects |
| 20:50:33 | Araq | it's hard to come up with a use case for blacklisting effects especially since the set of effects is open |
| 21:07:41 | * | Amrykid quit (Changing host) |
| 21:07:41 | * | Amrykid joined #nimrod |
| 21:11:30 | Araq | if (let m = input =~ re"abc"; m.isMatch): |
| 21:11:37 | Araq | echo m[0] |
| 21:11:38 | Araq | else: |
| 21:11:50 | Araq | echo m[1] # error: 'm' not declared |
| 21:12:10 | Araq | fine with everybody? |
| 21:12:27 | Araq | in other words the scoping rules for 'if' are slightly subtle :P |
| 21:12:41 | Araq | to support the above common use case |
| 21:12:52 | fowl | yea |
| 21:12:57 | fowl | i lik eit |
| 21:12:59 | gradha | looks weird when you "unroll" the if |
| 21:13:24 | Araq | it's crap if you have 'not' condition ;-) |
| 21:13:34 | fowl | if(let (good, res) = someFunc(); good): res.stuff |
| 21:14:02 | Araq | the real reason for supporting that is of course not 'if' but 'elif' |
| 21:14:36 | fowl | more parens = more accidental smileys |
| 21:14:40 | Araq | because for 'elif' you can't simply move it out of the condition |
| 21:15:14 | Araq | no smileys for me here |
| 21:15:53 | fowl | Araq: sometimes i'd love to be able to use _ and digits to join idents |
| 21:16:17 | fowl | at least inside `s |
| 21:16:26 | Araq | huh? you can do that already? |
| 21:16:45 | gradha | isn't in essence the if only checking the value of the last expression? sounds like you could rewrite that if construct as: |
| 21:16:49 | gradha | previous_statements |
| 21:16:56 | gradha | if last_statement: |
| 21:16:58 | gradha | blah |
| 21:17:00 | gradha | else: |
| 21:17:02 | gradha | meh |
| 21:17:08 | fowl | Araq: no i mean proc `foo _ 42` = ... |
| 21:17:09 | Araq | gradha: read what I wrote :P |
| 21:17:12 | fowl | not `foo_42` |
| 21:17:36 | Araq | try the same for 'elif' to see why it's nice to have |
| 21:19:30 | gradha | don't understand, isn't the if of the elif just appended into the first else block for chaining? |
| 21:19:51 | Araq | elif (let c = f(); c): ... |
| 21:19:53 | Araq | becomes: |
| 21:19:56 | Araq | else: |
| 21:20:01 | Araq | let c = f() |
| 21:20:04 | Araq | if c: ... |
| 21:20:37 | Araq | do that a few times and watch your indentation explode |
| 21:20:53 | Araq | 'elif' is much nicer for chaining |
| 21:21:17 | gradha | errr... wait, what I was meaning is: "isn't nimrod already doing that internally?" |
| 21:22:02 | Araq | yeah in fact you could do the same with a helper template |
| 21:22:11 | Araq | now we have an explicit syntax for it |
| 21:24:02 | fowl | can i use a template anywhere i use a type or should i just use a type alias |
| 21:24:13 | Araq | use a type alias |
| 21:27:04 | Araq | fowl: what is the use case for `foo _ 42` |
| 21:27:41 | gradha | irc code formatting sucks so I ellaborated my question on https://gist.github.com/gradha/5492095 |
| 21:28:08 | fowl | Araq: i was writing a template to generate accessors with importcizzle |
| 21:28:54 | fowl | defgetter(name, ty): stmt = proc `get_ name`*: ty |
| 21:29:27 | Araq | gradha: you're correct: the expansion changes scoping |
| 21:29:37 | fowl | importc needed the name to be get_* |
| 21:30:06 | Araq | I still don't get it fowl |
| 21:30:28 | Araq | importc: "get_$1" ? |
| 21:30:55 | fowl | oh ._. |
| 21:32:37 | * | gradha quit (Quit: bbl, have youtube videos to watch) |
| 21:54:25 | NimBot | Araq/Nimrod 56e86ed Araq [+0 ±4 -0]: tester should work again; documented (;) |
| 21:56:24 | * | fowl quit (Read error: Connection reset by peer) |
| 22:14:11 | * | Roin quit (Ping timeout: 245 seconds) |
| 22:26:54 | * | OrionPK joined #nimrod |
| 22:28:24 | NimBot | Araq/Nimrod e3e6edf Araq [+0 ±1 -0]: re.nim compiles again |