--- Log opened Thu May 17 00:00:18 2007 |
00:22 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has joined #code |
00:22 | | mode/#code [+o Thaqui] by ChanServ |
00:23 | | Syloq [Syloq@NetAdmin.Nightstar.Net] has joined #code |
00:24 | | Syloq is now known as Syloqs-AFH |
00:29 | | ToxicFrog|W`rkn is now known as ToxicFrog |
00:54 | <@Chalcedon> | can anyone make a suggestion as to what this error might mean: Inconsistent accessibility: field type 'Ex14_17.Entry[]' is less accessible than field 'Ex14_17.Form1.directory' |
00:54 | | * Chalcedon is perplexed |
00:54 | <@Chalcedon> | oh, and directory is an Entry[] object. |
00:57 | | * Vornicus eyes. |
01:00 | | Syloqs-AFH [Syloq@NetAdmin.Nightstar.Net] has quit [Ping Timeout] |
01:09 | < ToxicFrog> | ... |
01:09 | < ToxicFrog> | I have no idea. |
01:09 | < ToxicFrog> | Unless .directory and .Entry are actually the same object or something? |
01:09 | < ToxicFrog> | And have different permissions? |
01:09 | | * ToxicFrog shrugs |
01:10 | <@Chalcedon> | they should be two different objects from the same class |
01:10 | <@Chalcedon> | or, maybe I'm confused |
01:11 | <@Chalcedon> | I played with the public/private settings but that gave me more problems |
01:11 | < ToxicFrog> | Pastie the code? |
01:11 | | * ToxicFrog ponders what the hell he's going to have for dinner |
01:11 | <@Chalcedon> | I gave up :) |
01:11 | <@Vornicus> | Chicken sammiches |
01:12 | <@Vornicus> | With evil sauce. |
01:12 | < ToxicFrog> | I don't have enough chicken left for a sammich. |
01:12 | <@Chalcedon> | I'm going to work on my assignment considering it's due in a couple of weeks and I still have my stats one to do as well. |
01:12 | <@Chalcedon> | I understand classes, I also understand arrays. Those are the important bits |
01:12 | < ToxicFrog> | (actually - what do you mean by 'directory is an Entry[] object'? Is Entry a type?) |
01:12 | <@Chalcedon> | entry is a class |
01:13 | <@Chalcedon> | well, Entry |
01:13 | < ToxicFrog> | class is a subset of type, so |
01:13 | <@Chalcedon> | ah. |
01:13 | < ToxicFrog> | (if so, does this mean C# has first-class classes? Or is Ex14_17 a namespace or something?) |
01:13 | < ToxicFrog> | That is to say, classes are the means by which you create new types. |
01:13 | <@Chalcedon> | Ex14_17 is, I think a namespace, it's the name of the file at anyrate. |
01:13 | < ToxicFrog> | Ok. |
01:14 | < ToxicFrog> | I _think_, then, that it's saying something along the lines of "Form1.directory, which is an Entry, is accessible to things that can't access the original Entry declaration; this is not allowed" |
01:14 | <@Chalcedon> | the most sensible thing I could think of to do with it was to use some kind of list.append method. |
01:14 | <@Chalcedon> | however, my textbook only covers arrays, not lists |
01:15 | <@Chalcedon> | ah, yes. That would make sense. |
01:19 | < ToxicFrog> | ...aiuhgsudahkjasdfhgjkdfshg |
01:19 | < ToxicFrog> | Now I remember. |
01:19 | < ToxicFrog> | I was going to have eggrice for dinner. |
01:19 | < ToxicFrog> | The rice is still at work ;.; |
01:20 | <@Chalcedon> | :( |
01:21 | | * Chalcedon feeds TF quiche |
01:21 | < ToxicFrog> | So...cook more rice here and use that; make something pasta-related (I'm low on sauce materials, though); make a tuna melt... |
01:24 | | ReivClass is now known as Reiver |
02:29 | | gnolam [lenin@Nightstar-13557.8.5.253.se.wasadata.net] has quit [Quit: Z?] |
02:53 | | Reiver is now known as ReivClass |
02:58 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has quit [Ping Timeout] |
04:15 | | Derakon[AFK] [~Derakon@Nightstar-12737.sea2.cablespeed.com] has joined #code |
04:15 | | Derakon[AFK] is now known as Derakon |
04:16 | | * Derakon eyes his terrain physics code. |
04:16 | < Derakon> | Last time I worked on this, I thought I had something that basically worked, but it turns out it only works for flat ground. This is, um, not so useful. |
04:17 | < Derakon> | ...okay, that was a trivial fix. ¬.¬ |
04:18 | <@Vornicus> | pff |
04:18 | <@Vornicus> | What'd you do wrong? |
04:18 | < Derakon> | I was using back-out code to move the player out of intersection with terrain, and I was using as a back-out angle the surface normal of the terrain instead of the player's velocity. |
04:18 | < Derakon> | The ultimate side-effect being that when the player was theoretically at rest on sloped terrain, he'd gradually slide down it. |
04:21 | < Derakon> | Hrm...there is the small matter now that if the slope of the terrain is sharper than your diagonal jump velocity, then you teleport to the other side of the block... |
04:21 | < Derakon> | I suppose I can fix that by improving the player's vertical jump, though. |
04:25 | | ReivClass is now known as Reiver |
04:32 | < Derakon> | If the dot product is positive then the vectors do not oppose, right? |
04:33 | <@Vornicus> | Right |
04:33 | < Derakon> | Excellent. |
04:34 | <@Vornicus> | A?B = ||A|| * ||B|| * cos(?) |
04:35 | < Derakon> | Or alternatively x1x2+y1y2. |
04:36 | <@Vornicus> | I'm using the identity that shows you the angle bits. |
04:36 | | * Derakon prevents teleporting through the ground, woot. |
04:36 | <@Vornicus> | woot |
04:36 | < Derakon> | At least, in that particular method. ¬.¬ |
04:39 | | * Derakon tries to remember how to initialize a table with multiple key-value pairs in a single statement. |
04:41 | < ToxicFrog> | Which language? |
04:41 | < Derakon> | Lua, natch. |
04:41 | < ToxicFrog> | { foo=bar; baz=moby; } |
04:41 | < Derakon> | My mind is like unto a sieve. |
04:41 | < ToxicFrog> | Seperate them with ; or , |
04:41 | < Derakon> | Danke. |
04:44 | | * ToxicFrog slwwp |
04:44 | < Derakon> | Night. |
04:53 | < Derakon> | And now my normals implementation is vaguely sane, in the "each block has four normals and I've written a getNormal function" sense. |
04:56 | < Derakon> | And now I can bop my head on the ceiling, though I occasionally teleport to the right...I need a "getCenter" function for my sprites. |
05:12 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has joined #code |
05:12 | | mode/#code [+o Thaqui] by ChanServ |
05:22 | < MyCatVerbs> | Hrmn. If you added to C an equivalent to Lisp's (let (())) statement, hence allowing yourself to control the evaluation of functions in cpp macros, you could avoid (or even deliberately invoke in clever ways, heehee) the multiple-evaluation-sideeffects problem in C. |
05:23 | < MyCatVerbs> | And thereby make programming by means of truly frightening macro expansions in C a little less dangerous. Or more so, with clever abuse. ^^ |
05:24 | < Derakon> | I rather prefer my code to be predictable. |
05:31 | | Pi [~sysop@Nightstar-6875.hsd1.wa.comcast.net] has quit [Ping Timeout] |
05:31 | | Raif [~corvusign@Nightstar-22484.hsd1.ca.comcast.net] has quit [Ping Timeout] |
05:31 | | Raif [~corvusign@Nightstar-22484.hsd1.ca.comcast.net] has joined #Code |
05:31 | | mode/#code [+o Raif] by ChanServ |
05:32 | | Pi [~sysop@Nightstar-6875.hsd1.wa.comcast.net] has joined #code |
05:32 | | mode/#code [+o Pi] by ChanServ |
05:36 | < Derakon> | Mph. Given a player of arbitrary shape and a square block, the two of which are colliding with the player having a velocity and the block being fixed, how do I determine which edge of the block the player hit? |
05:36 | < Derakon> | Straight-up position or BB comparisons don't cut it. Neither does a basic velocity check. |
05:42 | | GeekSoldier|Sleep is now known as GeekSoldier |
05:43 | <@Raif> | That's a big subject. |
05:43 | <@Raif> | 2D or 3D/ |
05:43 | < Derakon> | 2D. |
05:43 | < Derakon> | The block is axis-aligned, too. |
05:44 | <@Raif> | Define "Arbitrary shape" |
05:44 | < Derakon> | Such that I'm using pixel-based collision detection. |
05:44 | <@Raif> | And you want to know what edge the player hit. Why doesn't velocity help? |
05:45 | < Derakon> | I'm sure it does. It doesn't do it on its own, though. |
05:45 | < Derakon> | A player moving up and to the right can hit the left *or* lower edges. |
05:46 | <@Raif> | Ok, if you're going per pixel anyway, and this might very well be brute force, draw a ray from each edge pixel's start to it's final position, and the ray most inside the block determines which edge it hit. |
05:46 | < Derakon> | Erk, no. |
05:46 | <@Raif> | How accurate do you need? |
05:46 | < Derakon> | Sufficient to not glitch out all the time. |
05:46 | < Derakon> | Mathematical perfection is not an issue. |
05:47 | <@Raif> | That method works, and considering it's only used on the player should be plenty fast for your needs. |
05:47 | < Derakon> | Except it'll need to be used on any physics-enabled object. |
05:48 | <@Raif> | I argue you opened this can of worms when you decided you wanted per-pixel physics. :P |
05:48 | < Derakon> | I want per-pixel physics because pure bounding boxes are too crude, but anything more detailed is too expensive. |
05:48 | <@Vornicus> | Polygons are cheaper, I think. |
05:48 | < Derakon> | Last time I got involved in collision detection I was using bounding polygons, and the detection routines never worked properly. >.< |
05:49 | <@Raif> | If you only do the edge pixels, you're saving a lot of calculations. If you want to sacrifice some accuracy and end up with occasional glitches, use all the convex corners of the sprite. |
05:49 | <@Raif> | And vorn's right, polygons are way cheaper. |
05:49 | <@Raif> | Anything beyond the above will require you to generate polygons anyway. |
05:49 | <@Vornicus> | Convex ones are incredibly cheap. |
05:49 | < Derakon> | And fairly crude. |
05:50 | <@Raif> | Cheap, fast, good: Pick two. |
05:50 | < Derakon> | What's the "fast and good" option? |
05:51 | <@Vornicus> | ...what's the difference between cheap and fast in this case anyway? |
05:51 | <@Raif> | Complex algorithms that you're not gonna want to deal with. :) |
05:51 | <@Raif> | cheap == developer time. fast == run time. |
05:51 | < Derakon> | Heh. |
05:51 | <@Raif> | s/==/=/g |
05:51 | <@Raif> | I love sed. |
05:51 | | * Derakon idly notes just how much he hates implementing physics. It's always such a pain to debug. |
05:52 | <@Raif> | That it is. |
05:52 | <@Raif> | Having written a couple physics engines, you don't need to worry about speed quite as much as you think in 2D. |
05:53 | <@Raif> | But I recommend trying to polygonize your physics sprites and going from there. |
05:54 | < Derakon> | I'll note for the record that even convex polygon collision is not exactly pretty to write. |
05:54 | <@Raif> | Work with the vertices first. If that's not high enough accuracy you can worry about the line segments. :) |
05:54 | <@Raif> | Physics is not pretty to write. |
05:54 | < Derakon> | It's fast and accurate, but I dan't pretend to understand how it works. |
05:55 | <@Raif> | Vorn: Thoughts? |
05:56 | <@Vornicus> | You seem to have covered all the ground I can. |
05:56 | <@Vornicus> | All I really know is that it's really not that hard to do convex poly collision and sorta figure out how the collision happened. |
05:57 | <@Raif> | Indeed. |
05:58 | <@Raif> | Der: Google will be your friend on this one. :) Basically, just sweep each vertex of your object polygon as a ray, find where each crosses the boundaries of the box. |
05:58 | < Derakon> | I have bad memories of doing polygon-based collision detection. >.< |
05:58 | < Derakon> | I've done this before, Raif. As I said, bad memories. |
05:59 | < Derakon> | Also, making bounding polys for each frame of animation is a pain. |
05:59 | <@Raif> | It's that or per-pixel. :) |
05:59 | < Derakon> | I find it hard to believe that there's no reasonably reliable way to determine which of four normals to use given two bounding boxes and a velocity. |
05:59 | <@Raif> | (per pixel would really just be very high res bounding polygons anyway) |
06:00 | <@Raif> | There is, but you have to be willing to sacrifice accuracy that you don't seem willing to sacrifice. |
06:01 | <@Vornicus> | Thing about per pixel is that you don't get anything pretending to resemble surface normals, either |
06:01 | <@Raif> | Now, if you're willing to make the player a bounding box, this all gets way easier. :) |
06:01 | < Derakon> | I'm willing to sacrifice accuracy so long as it doesn't result in gross destruction of suspension of disbelief. |
06:02 | < Derakon> | ...mph. Guess I should consider if partially-constricted bounding boxes are sufficient. |
06:02 | <@Raif> | So, if you have to AA bounding boxes, the goal is to find the exact point at which the boxes connect, then find in which direction they're overlapping. |
06:02 | <@Raif> | So, step 1) Do the boxes hit? (trivial) |
06:02 | < Derakon> | I do box-based CD already, for pruning purposes. |
06:03 | <@Raif> | Step 2) Sweep the boxes along each axis as points, find where the rays cross. This gives you a time TX and TY at which the nearest vertical and horizontal edges collide. |
06:03 | < Derakon> | But yeah, find the cointained vertex, multiply its containment by its velocity along each axis, find the longest. |
06:03 | < Derakon> | Or do the sweep if you want to get fancy. ¬.¬ |
06:04 | <@Raif> | That's how I'd do it. |
06:06 | <@Raif> | Anyway, you have the times at which each edge of the box would come in contact. Just use the greater time (because they both have to hit before the boxes are considered to have connected, of course). |
06:06 | <@Raif> | thus if the boxes collide on the Y axis AFTER they collide on the X axis, then you'd reflect vertically. |
06:06 | < Derakon> | Yeah, I've done this logic before. I was mainly just hoping to avoid it. ¬.¬ |
06:07 | <@Raif> | :P |
06:07 | <@Raif> | It's not all that bad. |
06:07 | <@Raif> | I had to do this with OBB's in 3d. |
06:07 | <@Raif> | Now THAT was non-fun. |
06:07 | < Derakon> | I guess I'll see what things look like if I just use AABBs that are chopped a few pixels off in each direction. |
06:07 | < Derakon> | Heh. |
06:08 | < Derakon> | (The "chop a few pixels off" trick works well because we're more willing to believe in close shaves than in collisions that clearly didn't happen) |
06:08 | <@Raif> | Depends how fast your objects are moving. |
06:08 | <@Raif> | But yeah, I agree. :) |
06:08 | <@Raif> | Generally, when that stuff matters I start using circles.e |
06:09 | < Derakon> | 3D spherical collision detection - every physicist's best friend. ;) |
06:09 | <@Raif> | Combination circles and AABB's get you 90% of the way there, and most people don't notice the last 10%. : |
06:09 | <@Raif> | Fuckin' right. :) |
06:10 | <@Raif> | One of the physics engines I wrote was for extremely high velocity, high density spheres. |
06:10 | < Derakon> | Heh. |
06:10 | <@Raif> | The first means sweeping, and the second means stacking... which makes for an interesting problem. |
06:11 | < Derakon> | Some classmates of mine did a project on fluid dynamics that I think was just iterating that over and over again. |
06:11 | <@Raif> | Probably. At a low level, that's what loose fluids (like air) do. |
06:12 | <@Raif> | For actual fluids, I don't think it'd work very well. You'd have to take viscosity into account, though pressure would be pretty nicely handled. |
06:12 | < Derakon> | Well, no. They were dealing with smoke, as I recall. |
06:12 | < Derakon> | They actually tossed their particles into POV-Ray and rendered them as tiny spheres. Looked interesting. |
06:13 | <@Raif> | Ah, see statement one then. :) |
06:13 | <@Raif> | funny. |
06:13 | | * Raif went to a school where all that stuff was expected to be real time, though POV would have been way prettier most of the time. |
06:13 | <@Raif> | and easier, when you don't have TA's trying to find the breaking limits. :P |
06:14 | <@Raif> | It's static video! Take that, assbag graders! |
06:14 | < Derakon> | Yeah, I think they wanted to do realtime, and then they discovered that at any quality level that looked decent, they needed several minutes to process each frame. |
06:16 | <@Vornicus> | heh |
07:09 | | Derakon is now known as Derakon[AFK] |
08:07 | | You're now known as TheWatcher |
08:49 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has left #code [Leaving] |
08:52 | | KBot [~karma.bot@Nightstar-29036.neoplus.adsl.tpnet.pl] has joined #Code |
08:52 | | KarmaBot [~karma.bot@Nightstar-29655.neoplus.adsl.tpnet.pl] has quit [Ping Timeout] |
08:53 | | KBot is now known as KarmaBot |
08:53 | | DarthEpt [~farkoff@Nightstar-29655.neoplus.adsl.tpnet.pl] has quit [Ping Timeout] |
09:00 | | AnnoDomini [~farkoff@Nightstar-29036.neoplus.adsl.tpnet.pl] has joined #Code |
09:00 | | mode/#code [+o AnnoDomini] by ChanServ |
09:03 | | AnnoDomini [~farkoff@Nightstar-29036.neoplus.adsl.tpnet.pl] has quit [Ping Timeout] |
09:17 | | You're now known as TheWatcher[afk] |
09:43 | | Mahal [~Mahal@Nightstar-12512.worldnet.co.nz] has quit [Quit: reboot] |
09:46 | | Mahal [~Mahal@Nightstar-12512.worldnet.co.nz] has joined #Code |
09:46 | | mode/#code [+o Mahal] by ChanServ |
10:03 | | Mahal is now known as MahalBed |
10:10 | <@Chalcedon> | does anyone have any suggestions on a random number generator which consistently returns the same number? |
10:10 | <@Chalcedon> | as in, it's called four times and at least half the time it returns the same 4 numbers. |
10:12 | | You're now known as TheWatcher[wr0k] |
10:13 | | Chalcy [~Chalcedon@Nightstar-1216.ue.woosh.co.nz] has joined #code |
10:13 | | mode/#code [+o Chalcy] by ChanServ |
10:14 | | Chalcedon [~Chalcedon@Nightstar-1216.ue.woosh.co.nz] has quit [Ping Timeout] |
10:14 | <@Chalcy> | if anyone responded.... thanks for your help but apparently Visual studio doesn't have an autosave or an auto recover and it doesn't do a proprer user initiated save until you exit the program. |
10:14 | | Chalcy is now known as Chalcedon |
10:15 | <@Chalcedon> | so... program down drain. |
10:18 | | Chalcedon [~Chalcedon@Nightstar-1216.ue.woosh.co.nz] has quit [Quit: Gone] |
11:38 | | GeekSoldier_ [~Rob@Nightstar-4666.pools.arcor-ip.net] has joined #code |
11:38 | | gnolam [lenin@Nightstar-13557.8.5.253.se.wasadata.net] has joined #Code |
11:39 | | mode/#code [+o gnolam] by ChanServ |
11:39 | | GeekSoldier [~Rob@Nightstar-4401.pools.arcor-ip.net] has quit [Ping Timeout] |
12:13 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has joined #code |
12:13 | | mode/#code [+o Thaqui] by ChanServ |
12:15 | | Reiver is now known as ReivZzz |
13:28 | < ToxicFrog> | ...oh, pffftfhahahah |
13:28 | < ToxicFrog> | BrockSamson: Although there is a GetHeadingPitch() for the weapons and manipulators there doesn't appear to be a GetHeadingYaw()? |
13:28 | < ToxicFrog> | o: Ok, this is going to sound stupid because, well, it is. GetHeadingPitch() actually returns both yaw and pitch. Even worse, it returns them in that order. |
13:28 | < ToxicFrog> | yaw, pitch = manip:GetHeadingPitch() |
13:37 | | AnnoDomini [~farkoff@Nightstar-29036.neoplus.adsl.tpnet.pl] has joined #Code |
13:37 | | mode/#code [+o AnnoDomini] by ChanServ |
14:11 | < TheWatcher[wr0k]> | bash gurus - is there a quick way to convert the contents of a variable to lowercase? |
14:25 | < ToxicFrog> | Yes. |
14:25 | < ToxicFrog> | Well, ther' |
14:25 | < ToxicFrog> | Well, there's probably several, but the one that comes to mind: |
14:26 | | Thaqui [~Thaqui@Nightstar-25913.jetstream.xtra.co.nz] has left #code [Leaving] |
14:26 | < ToxicFrog> | FOO=`echo "$FOO" | tr [A-Z] [a-z]` |
14:26 | < ToxicFrog> | There |
14:26 | < ToxicFrog> | 's likely a more elegant approach, thought. |
14:27 | < TheWatcher[wr0k]> | *shrug* that works, thanks. |
14:30 | < ToxicFrog> | function tolowercase() { eval $1=`echo "${!1}" | tr [A-Z] [a-z]`; return 0; } |
14:31 | < ToxicFrog> | No more elegant, but easier to use. |
15:31 | | GeekSoldier_ is now known as GeekSoldier |
15:39 | | Derakon[AFK] [~Derakon@Nightstar-12737.sea2.cablespeed.com] has quit [Connection reset by peer] |
17:13 | | You're now known as TheWatcher[afk] |
17:57 | | ToxicFrog is now known as ToxicFrog|W`rkn |
18:24 | | You're now known as TheWatcher |
18:57 | | You're now known as TheWatcher[afk] |
19:40 | | You're now known as TheWatcher |
19:46 | | MahalBed is now known as Mahal |
19:54 | | Mahal is now known as MahalGone |
20:08 | | GeekSoldier is now known as GS|Sleeps |
20:59 | | Chalcedon [~Chalcedon@Nightstar-1216.ue.woosh.co.nz] has joined #code |
20:59 | | mode/#code [+o Chalcedon] by ChanServ |
22:35 | < MyCatVerbs> | ToxicFrog|W`rkn: does Lua have any of: first-class functions, partially applied functions, closures, pattern matchin? |
22:36 | < MyCatVerbs> | (Please?) |
22:37 | < ToxicFrog|W`rkn> | Yes, I don't know what those are, yes, please clarify question. |
22:38 | < ToxicFrog|W`rkn> | If by #4 you mean regexes, yes. |
22:38 | < ToxicFrog|W`rkn> | If you mean, say, multiple dispatch, no but it's easy to add. |
22:40 | < MyCatVerbs> | ToxicFrog|W`rkn: partial application, like in Haskell I can say "let inc = (+) (1::Integer)" and it defines a function inc of type Integer->Integer from the function (+) which had type Integer->Integer->Integer. |
22:40 | <@Chalcedon> | can anyone suggest why a random() method when called four times in a row would return the same four numbers about half the time? |
22:41 | < MyCatVerbs> | ToxicFrog|W`rkn: I think I mean multiple dispatch. Things like being able to say 'foo Nothing = "Nothing found"; foo Just a = show a' |
22:41 | < MyCatVerbs> | Chalcedon: what're you seeding the generator from?j |
22:41 | <@Chalcedon> | uh |
22:41 | < ToxicFrog|W`rkn> | Aah, pattern matching on function arguments. Which is not the same as multiple dispatch since it matches on values, not types. |
22:42 | <@Chalcedon> | I don't think I specified a seed, so whatever the default is. |
22:42 | | * Chalcedon investigates. |
22:42 | < ToxicFrog|W`rkn> | Not intrinsically. You can create something equivalent, but that's loosely true of any language, since pattern matching is (AFAICT) in the syntax, not the semantics. |
22:43 | < MyCatVerbs> | Chalcedon: that sounds like it's probably the source of your problem. Traditional method is just to call randomseed(current_time) for whatever seeding and time-getting functions your language provides. |
22:43 | < ToxicFrog|W`rkn> | As for partial application - er, how is this any different from: |
22:43 | < ToxicFrog|W`rkn> | function inc(foo) return add(foo, 1) end |
22:43 | < ToxicFrog|W`rkn> | (tail-recursive, BTW) |
22:44 | < MyCatVerbs> | ToxicFrog|W`rkn: I suppose it isn't. Just a handy syntax for creating closures. |
22:44 | < ToxicFrog|W`rkn> | That's not even a closure, though. |
22:44 | < ToxicFrog|W`rkn> | It's - depending on how the language implements it - either a macro or a tail-recursive function call or a wrapper. |
22:45 | < MyCatVerbs> | ToxicFrog|W`rkn: you're closing over the provided number one there. Some minor generalisation of inc might return add (foo, n) for some provided n. |
22:45 | <@Chalcedon> | ok, the help file just told me the same thing... but not how to do it. |
22:45 | < MyCatVerbs> | Chalcedon: what language are you working in then, please? |
22:45 | < ToxicFrog|W`rkn> | MyCatVerbs: no you aren't, it's a constant! |
22:45 | <@Chalcedon> | C# |
22:45 | < MyCatVerbs> | Chalcedon: bollocks, I don't know then. |
22:46 | < ToxicFrog|W`rkn> | Chalcedon: in C, the function is srand() (seed-random) |
22:46 | < ToxicFrog|W`rkn> | But that probably doesn't help. |
22:46 | <@Chalcedon> | well, I shall keep perusing the help file to see if it produces something useful |
22:46 | <@Chalcedon> | could be this one -> // Create a Random object with the specified seed. |
22:47 | < MyCatVerbs> | Chalcedon: yes. |
22:47 | < ToxicFrog|W`rkn> | Assuming that Random is the random number generator class, yes. |
22:47 | <@Chalcedon> | or rather the timer one which is next. |
22:47 | | * Chalcedon nods at TF |
22:47 | < ToxicFrog|W`rkn> | MyCatVerbs: ok, I've looked up partial application. |
22:47 | | * Chalcedon supplies cookies in thanks |
22:48 | < ToxicFrog|W`rkn> | AIUI, it's a function->function mapping such that the result 'stores' some arguments, and when called with the remainder invokes the original function with the complete set. |
22:48 | < ToxicFrog|W`rkn> | Similar to currying. |
22:48 | < ToxicFrog|W`rkn> | And, yes, this is not only possible but completely trivial in Lua. |
22:49 | < MyCatVerbs> | ToxicFrog|W`rkn: it *is* currying, I think. What's the distinction I'm missing between that and a closure? |
22:49 | < ToxicFrog|W`rkn> | Well, first of all, closures are something else again. |
22:50 | < ToxicFrog|W`rkn> | They're a function that executes in the lexical scope it was declared in even when called from outside it. |
22:50 | < ToxicFrog|W`rkn> | They are used to implement currying and partial application, but are not the same thing. |
22:50 | < MyCatVerbs> | Ohhh. |
22:50 | < MyCatVerbs> | Doesn't that play merry Havok with block scoping? |
22:50 | < ToxicFrog|W`rkn> | I don't understand the question. |
22:51 | < MyCatVerbs> | It isn't sensible, nevermind. |
22:52 | < MyCatVerbs> | ToxicFrog|W`rkn: if I understand that correctly, closures can behave totally differently between CL and Scheme because their scoping rules are different? |
22:52 | < ToxicFrog|W`rkn> | Anyways. Currying, AIUI, is a more specific form of partial application, with one argument per layer. |
22:53 | < ToxicFrog|W`rkn> | You can use either to implement the other fairly easily. |
22:53 | < MyCatVerbs> | Seems like a bit of a thin distinction to make, whether you supply one argument or several. |
22:54 | < ToxicFrog|W`rkn> | It's a fuzzy distinction. |
22:54 | < ToxicFrog|W`rkn> | Sufficiently fuzzy that no-one can agree whether the Python partial application module is actually currying or not. |
22:54 | < ToxicFrog|W`rkn> | As for the scoping rules, again, I don't know CL's scoping rules, so I can't really answer the question meaningfully. |
22:54 | < MyCatVerbs> | Sweet. |
22:55 | < ToxicFrog|W`rkn> | However, the way closures work is, say you declare a function in a context where certain variables are in scope. |
22:55 | < ToxicFrog|W`rkn> | The function makes some use of those variables. |
22:55 | < MyCatVerbs> | They're messy, put it that way. "Dynamic scoping." You can do things like flet whose effects somehow propogate into really bizarre places you'd never expect them to. |
22:55 | | * MyCatVerbs nods. |
22:56 | < ToxicFrog|W`rkn> | Now - and since functions are first-class, this is completely possible - you acquire, and call, the function in some other context where those variables are not in scope. |
22:56 | < MyCatVerbs> | Yuhuh. |
22:56 | < ToxicFrog|W`rkn> | The caller still can't access them, but the called function still works. |
22:56 | | * Vornicus <3 first-class functions |
22:56 | < MyCatVerbs> | Did the closure take a copy of those variables, or are the originals being referred to? |
22:57 | < ToxicFrog|W`rkn> | The latter, although there are some subtleties. |
22:57 | < MyCatVerbs> | Also, oh, fuck, no wonder I can't work out where closures fit into Haskell. They don't, at all, because they revolve around mutable state. x_x |
22:57 | < MyCatVerbs> | Thanks. |
22:58 | < MyCatVerbs> | The amount of your time I've wasted bugging you with stupid questions over the years, I think I owe you some seriously frightening quantity of alcohol by now. |
22:58 | < ToxicFrog|W`rkn> | I don't drink, but computer hardware is an acceptable alternative ?? |
22:59 | < MyCatVerbs> | Heh. That seems to be a surprisingly common thing amongst the better programmers I know. |
22:59 | < ToxicFrog|W`rkn> | Anyways. The subtlety is mainly that each time the scope is evaluated, new copies of any upvalues are created - so if you have a function that returns two other functions that refer to locals, and you call that function twice, the first pair of functions returned will refer to the same set of locals, and the second pair will also refer to the same ones as each other, but not the same ones as the first pair. |
22:59 | < ToxicFrog|W`rkn> | Which makes this quite handy. |
23:00 | < ToxicFrog|W`rkn> | In conclusion, function closures are love. |
23:00 | < MyCatVerbs> | Whoa, grody. That being one of those evil tricks with which you can implement objects using closures? =) |
23:03 | < ToxicFrog|W`rkn> | Yep. The class definition is a function, the object is a closure (or a set of closures with shared upvalues) |
23:03 | < ToxicFrog|W`rkn> | In Lua it's easier to implement OO in terms of tables and metamethods, though. |
23:03 | < MyCatVerbs> | Nice. |
23:04 | < ToxicFrog|W`rkn> | (metamethods == operator fallbacks. With use of proxy objects they become operator overloads instead.) |
23:04 | < MyCatVerbs> | Er, metamethods? Are they some form of equivalent to multiple dispatch with slightly different semantics? |
23:04 | < MyCatVerbs> | Oh, okay. Wait, what? |
23:05 | < ToxicFrog|W`rkn> | By fallback, I mean it'll be called only if the default operator behaviour is undefined or fails. |
23:05 | < MyCatVerbs> | You can implement OO from scratch in a language that doesn't have it already. Well and good. You can implement operator overloading too!? |
23:05 | < ToxicFrog|W`rkn> | Well, it already has operator fallbacks. |
23:05 | < ToxicFrog|W`rkn> | Without that we couldn't implement operator overloads. |
23:05 | < ToxicFrog|W`rkn> | And overloads are just a matter of jiggering the object so that the default operations always fail or are undefined, so it always uses the fallback instead. |
23:06 | < ToxicFrog|W`rkn> | You can do most of that with a proxy table, but if you want to do it right and overload __len too, you have to use a proxy fuserdata. |
23:06 | | * Chalcedon eyes C# |
23:06 | < MyCatVerbs> | That sounds suspiciously similar to the RPC trick in SmallTalk, where you'd define an object that had *no* methods, and passed all unknown methods along to a TCP/IP socket. |
23:07 | < ToxicFrog|W`rkn> | Also, it's flexible; you can create your own metafields. Such as __pairs to overload iteration behaviour (hint: wrap the pairs() function with something that checks for that) or __type for objects that refers to their class definition. |
23:07 | < ToxicFrog|W`rkn> | Yeah, you can do that. |
23:07 | < ToxicFrog|W`rkn> | Just use the __newindex metamethod. |
23:07 | < MyCatVerbs> | (Er, serialised them at, anyway.) Whereupon there'd be another object on the machine on the other side of that connection, deserialising method calls and actually performing them. |
23:07 | < ToxicFrog|W`rkn> | Lua serializes well, too, although some work is needed to protect against malicious structures if you're recieving over the network or other untrusted sources. |
23:08 | | * ToxicFrog|W`rkn nods |
23:08 | < ToxicFrog|W`rkn> | Yeah, this is a case of "been there, done that" |
23:08 | < MyCatVerbs> | Well jah, if working in a dynamic language you're probably better off writing your own parser. |
23:08 | < ToxicFrog|W`rkn> | ...why? |
23:08 | < ToxicFrog|W`rkn> | loadstring(str) -- parses str and returns the parsed and compiled bytecode chunk as a function |
23:09 | < MyCatVerbs> | Well, it doesn't have C's disadvantage that parser writing is risky and fills the program with vulnerabilities. |
23:09 | < ToxicFrog|W`rkn> | string.dump(fn) -- returns the bytecode as a string suitable for use with loadstring() |
23:09 | < MyCatVerbs> | And it does let you write a very minimalist parser which doesn't have the ability to call any dangerous functinos. |
23:09 | < ToxicFrog|W`rkn> | Eh. |
23:09 | < ToxicFrog|W`rkn> | You don't need that at all. |
23:09 | < ToxicFrog|W`rkn> | If you want to avoid dangerous functions, you use setfenv() to restrict what the function can access. |
23:10 | | * MyCatVerbs ponders threaded Lua. |
23:10 | < ToxicFrog|W`rkn> | That also protects against namespace pollution. |
23:10 | < MyCatVerbs> | ToxicFrog|W`rkn: oooh, nice. |
23:10 | < ToxicFrog|W`rkn> | Which just leaves infinite loops, which can be removed with a simple lexical transform or by temporarily applying a debug hook. |
23:11 | < MyCatVerbs> | ToxicFrog|W`rkn: what if somebody tried to throw your program into an infinite loop or something though? I think you had that worry a while back. |
23:11 | < MyCatVerbs> | Wait, you found a good solution? |
23:11 | < MyCatVerbs> | Awesome. |
23:11 | < ToxicFrog|W`rkn> | As for threads - Lua has intrinsic support for coroutines. |
23:11 | < ToxicFrog|W`rkn> | For realtime/preemptive threading, I've written a message-passing library, and someone else has written a pthreads-like library. |
23:12 | < ToxicFrog|W`rkn> | (in C, sadly; realtime threading is something you can't implement from entirely inside Lua) |
23:13 | < MyCatVerbs> | I was thinking of a layer done in C to make writing pool-of-worker-threads type daemons very easy, with things like automatic murder of any thread which eats excessive CPU time, etc. |
23:14 | < ToxicFrog|W`rkn> | Ummmm. |
23:14 | < ToxicFrog|W`rkn> | Message-passing is ideal for that kind of construct, but you'd have to implement assassination yourself. |
23:14 | < MyCatVerbs> | Does that sound insane? |
23:15 | < MyCatVerbs> | Well yeah, the main reason for dragging C into it is for the sake of assassination. |
23:15 | < ToxicFrog|W`rkn> | And I'm not actually sure how you'd figure CPU time on a per-thread basis; POSIX doesn't seem to have an API for it. |
23:15 | < ToxicFrog|W`rkn> | Well, no, the main reason for dragging C into it is so that you can do realtime threading in the first place. |
23:18 | < ToxicFrog|W`rkn> | per-thread signal handling and that sort of thing is a big can of worms I didn't even try to open; there's no guarantee that the Lua state will be consistent when you enter the signal handler. |
23:21 | < MyCatVerbs> | You could host multiple Lua 'terp instances, allow only restricted communication between them. |
23:22 | < MyCatVerbs> | Some form of strict by-value CSP. Actually implement it with shared memory under the hood, but only *expose* the strict semantics. |
23:32 | < ToxicFrog|W`rkn> | That's actually what I did. |
23:32 | < ToxicFrog|W`rkn> | Well, the seperate VMs part. |
23:32 | < ToxicFrog|W`rkn> | Shared memory was a big no. |
23:32 | < ToxicFrog|W`rkn> | I mean, you can't really do that. |
23:32 | < ToxicFrog|W`rkn> | Not without terp hacking, anyways. |
23:33 | < ToxicFrog|W`rkn> | Instead it copies data between VMs on send() or reply(). |
23:33 | < ToxicFrog|W`rkn> | (well, on recieve(); send() buffers on the sender's stack) |
23:47 | < MyCatVerbs> | ToxicFrog|W`rkn: it's the semantics that're important though, right? The shared memory thing would just be a nice optimization to have, if feasible. |
23:47 | < MyCatVerbs> | Possibly not even worth the effort, if memcpy() happens to be faster than all the bookkeeping you'd need to do. |
23:48 | < ToxicFrog|W`rkn> | Yeah. The semantics aren't those of shared storage either, though. |
23:48 | < ToxicFrog|W`rkn> | As for memcpy() - it doesn't explicitly use that, because you -cannot- access VM internals. |
23:49 | < ToxicFrog|W`rkn> | It pops each value from the stack into C, then pushes the result into the other VM. |
23:49 | < MyCatVerbs> | Well, no. But shm would let you do things like "transfer" packets from one VM to the next without any actual copying of data, just a few pointers and locks being exchanged. |
23:49 | < ToxicFrog|W`rkn> | Internally this is probably memcpy() based. |
23:49 | < ToxicFrog|W`rkn> | Yeah. That's how SGOS does it. |
23:49 | < ToxicFrog|W`rkn> | But SGOS doesn't really have discrete processes. |
23:49 | < MyCatVerbs> | Whoa, really? |
23:49 | < MyCatVerbs> | You have zero-copy internal sockets? |
23:50 | < ToxicFrog|W`rkn> | Or rather, the distinction between processes and threads is very fuzzy; the entire system is shared memorty. |
23:50 | < ToxicFrog|W`rkn> | A message pass is a pointer pass and occurs in very few instructions. |
23:50 | < MyCatVerbs> | Eh, fuzzy enough. But still. |
23:50 | < ToxicFrog|W`rkn> | Which is why it scales up to 60 thousand threads. |
23:50 | < MyCatVerbs> | Cool. |
23:50 | < MyCatVerbs> | Like green threads, but in ring 0 just 'cuz. =) |
23:51 | < ToxicFrog|W`rkn> | Lua is the opposite; even when you have shared memory there's no way to VMs to refer to each other directly. |
23:51 | | You're now known as TheWatcher[T-2] |
23:51 | < MyCatVerbs> | That must make 'em fairly safe and stable as an upshot, though. |
23:52 | < ToxicFrog|W`rkn> | Quite. |
23:52 | < ToxicFrog|W`rkn> | In the threading library, the worst you can do is deadlock. |
23:52 | < MyCatVerbs> | It wouldn't be impossible to hack the VMs to pass data around like that, though, right? |
23:52 | < ToxicFrog|W`rkn> | And even that takes some work, since message-passing threads are implicitly locking. |
23:52 | < MyCatVerbs> | Spiffy. |
23:53 | < ToxicFrog|W`rkn> | No, it wouldn't; in particular, you could probably jigger it so that multiple VMs share the same table structure, and use locks to coordinate on it. |
23:53 | < MyCatVerbs> | Well, y'know, you can emulate more or less any set of concurrency primitives using any other complete set. So just emulate pthread-style locks, then deliberately acquire them in the wrong order. =) |
23:54 | < ToxicFrog|W`rkn> | I implemented pthread-style mutexes in it as an exercise. It was surprisingly easy. |
23:54 | | You're now known as TheWatcher[zZzZ] |
--- Log closed Fri May 18 00:00:18 2007 |