w Capital of Texas Triathlon Preview By greglsblog.blogspot.com Published On :: Sat, 28 May 2016 10:38:00 +0000 Monday I'm going to be running in the 25th Capital of Texas Triathlon! It's my first triathlon (Olympic distance) in twenty years and I'm pretty jazzed. Steely-eyed determination 20 years ago. :-) One of the great things about triathlons (and running races in general) is that you get to occupy unusual spaces: the last ones I did were Leon's Triathlon in Hammond, Indiana, a couple of Bud Light triathlons and others in Chicago. Leon's had a swim in Wolf Lake (shudder), followed by a cycle leg on an elevated highway that ran past the old U.S. Steel plant, and a run leg through an industrial downtown. The Chicago ones were on the lakefront, just north of Navy Pier, with a bike on Lake Shore Drive and a run along the lake. 2013 CapTexTri The CapTexTri also has a great location in downtown Austin, with a 1.5k swim in Lady Bird Lake; a 40k (24.8 mile) bike on a quadruple loop through downtown Austin, including Congress Avenue and Cesar Chavez; and a 10k (6.2 mile) run through Zilker Park. The only thing I'm not too keen on is the bike route, since it requires you to do the same loop four times with a bunch of corresponding hairpin turns. I don't like loop routes because I always think of how many more times I have to do the thing...Still, going up and down Congress Avenue without any cars is going to be pretty cool. As long as there are no poles in the middle of the road, I should be okay. :-). Don't ask. I feel fairly good about my training. I've maintained good running mileage after the Austin Marathon and Austin Distance Festival and got some good workouts in even while traveling doing school visits. On Stone Arch Bridge in Minneapolis The swim is probably my weakest event -- I could stand to do more work on technique and probably do more open water swimming, but the distance won't be an issue. Also, Lady Bird Lake isn't going to have waves (I seem to recall a couple of triathlons in Chicago with 3-4 foot waves on Lake Michigan (and this was on the near side of the breakwater). Also, I won't have to deal with a wet suit. My biggest concern is to not get kicked in the face. :-). Lady Bird Lake during 2013 CapTexTri The bike I'm feeling good about as well. I'll be using the bike I used for my triathlons back in the day - a Trek 1000 I bought when I was in grad school for $450 (a guy at one bicycle shop here tried to sell me a new one, asking if I had a "nostalgic attachment" to it.). I do, but I also don't think a new bike is going to drastically transform my performance. At least not $2000 worth :-). (A guy at another bike shop told me the Trek 1000 was his first road bike and he wished he still had it. It's possible he was being kind :-)). Tomorrow is packet pick-up, bike drop-off, and a chance to scope out the transition area, which I'll need because I can't see without my glasses...:-) Oh, well. Qapla! Full Article CapTexTri races triathlons
w Busy Writing and Running Summer By greglsblog.blogspot.com Published On :: Sat, 20 Aug 2016 22:32:00 +0000 Well, it's been a busy summer writing-wise. I'm letting a draft of a middle grade sci-fi adventure cure for a bit and also completed a work-for-hire project, and two-and-a-half nonfiction projects. (The half is still in-progress :-)). Circa 1995. No hills :-). After the Cap Tex Tri weather debacle, I reconsidered my original plan to try the Austin Half-Ironman (or Ironman 70.3 as they're calling the things these days). I'd wanted to do a couple Olympic distance races this summer (the other would've been the Tri Rock Austin Triathlon over Labor Day weekend) to get the kinks out before going for the longer distance. Unfortunately, the schedule didn't quite work out (and I'm going to be doing some school and bookstore visits in October, prime training time :-)). Also, this allows me to delay buying a new bike -- my current one is a 1989 Trek that is fine, but riding 50+ miles around the Hill Country, I can see where handlebar shifters would be useful :-). So I decided to dive back in to the Austin Distance Challenge and take up the Austin Runners Club on the marathon training (which would also help with next year's triathlons). My goal is a personal best or possibly Boston Marathon qualifying. (With the age-group corrections, BM qualifying has finally caught up with my PB :-)). The ARC program is based on the Runner's World "Run Less, Run Faster" program, which has you run three days a week and do other cardio work two days a week. One of the days is a track workout, one is a tempo run and the third is a long run, with pace times based on a one mile time trial we did a couple weeks ago. I have no idea if it will work, but I like it because I want to keep up the biking and running as well. After the long run I just completed the first week of the program and didn't actually hit any of my goal times, but I've never actually tried running for time, so at least the effort is interesting. I ran a trial mile of 7:10, slightly slower than my 6:50 from last spring and a lot slower than my PB of 5:55 (granted, twenty years ago :-)). From this, the track workout was supposed to be 4x1000 m at 4:09; my times were 4:20; 4:14; 4:15; and 4:22, so not terrible. The tempo workout was supposed to be 4 miles at a 7:38 pace and my actual pace was 7:46. I figured it would be a challenge to hit those marks but was glad to have been close. The long run was supposed to be 11 miles at 8:57, which I though I could do, no problem, since I'd done my half marathons last year at around 8:24. But with the humidity and heat (in August, hydration tends to be my biggest problem) and having only three hours of sleep (due to small feline mammals), I only did seven miles at a 9:07 pace. Based on limited data, I like the program because it's not just about racking up mileage, which was getting a bit old. Also, the track workouts are not far from where I live :-). Anyway, I'm looking forward to the challenge of a new marathon best time, at the 2017 Austin Marathon! Setting my PB on a wintry spring day Full Article races
w Cubs Win! By greglsblog.blogspot.com Published On :: Sun, 23 Oct 2016 03:55:00 +0000 Every Cubs fan is ten years old tonight. For the first time since 1945, the Cubs are in a World Series. They haven't won one since 1908. In that year, Harriet Tubman was still alive. So was Mark Twain. And Leo Tolstoy. And Geronimo. And Butch Cassidy and the Sundance Kid. My high school was founded that year. It's just baseball, yes, and I have philosophical objections to the culture of professional sports in this country and elsewhere. But let me repeat: in this, the Year of Our Lord Two Thousand and Sixteen, the Cubs are in the World Series. For all the years since '08, for all the years they had great players like Ernie Banks and Billy Williams and Ron Santo and Ryne Sandberg, this time, they finally, finally made it. For fans who remember 1945 and bovid mammals of the genus Capra; for those who recall the implosions of 1969 and 1984 and 2003, this time, they did it (Yeah, there were a couple other times they were in the playoffs since '84, but those never felt like their year). This time, they finally did it. I remember, in the 70s, my mother taking me and my brother and our friends to the Cubs games, especially on Fridays, which was Ladies' Day and tickets were cheap (Fridays didn't become popular until the 80s). It was the era of Reggie Jackson and the Pirates and the Big Red Machine of Cincinnati. There were peanuts outside and hot dogs inside and vendors selling Old Style beer (which of course we didn't drink). There were Andy Frain ushers and no one had even thought about putting seats on the roofs of buildings across the street. There was that deliciously analog giant scoreboard in center field. (And, of course, there were no big screen high definition TVs.). I remember our neighbor's cousin from Japan coming to see a baseball game in America and being wowed by Wrigley Field. I remember some of the coldest spring days of my life sitting along the unreserved seats of left field. I remember when the Cubs scored 22 runs in a single game. And lost. (I also remember when WGN replayed the game just because it was so awesome.). I remember when they installed lights and being relieved they architecturally matched the stadium. I remember commemorating the 50th anniversary of my high school's new building and the seventy-fifth anniversary of its founding by walking down Addison to see the Cubs play. And I remember when Hank Aaron came for his first appearance in Chicago after breaking Babe Ruth's home run record and the entire stadium stood and gave him a standing ovation even though he was on the other team. I remember Jack Brickhouse and being kind of disappointed when he retired and was replaced by Harry Caray who, of course, had covered the White Sox, which was just wrong. I remember friends being fans of the Reds and the Pirates and the Dodgers and the White Sox, which was just wrong. (For the record, I was not opposed to their winning the World Series a couple years back. I don't like their new stadium, though. Or the fact that they took Comiskey off the name). I totally shouldn't care about professional athletes making millions for their billionaire employers for mediocre performances over the course of a century. And part of me doesn't. But it's the Cubs. And today, every Chicagoan who remembers is ten years old again. And tonight, that's sublime. Even if they don't beat Cleveland. But they will. Unless they don't. In which case they will do so in the most heart-breakingly way possible. Because they're the Cubs. And it's what they do. And there will be a next year. Full Article
w Austin Ironman 70.3! (Race Weekend!) By greglsblog.blogspot.com Published On :: Thu, 22 Mar 2018 21:06:00 +0000 Okay, it's been a while, but I thought I'd finally post about the 2017 Austin Ironman 70.3 race weekend. :-). Like I mentioned in my last post, I felt fairly optimistic -- if anything I was a bit burned out on training. The big kicker, though, was that the weather was forecast to be 38 degrees race morning, which resulted in a bit of last-minute anxiety, mostly due to the mantra, "Don't do anything different on race day." That is, it is unwise in the extreme to test out new equipment or clothing on race day. Unfortunately, faced with the prospect of a 38 degree swim and bike ride (and the fact that it would warm up quickly), we had to make some last minute adjustments. The week before the race, I picked up a triathlon jersey that had sleeves, and borrowed some arm warmers from one of my training partners. Saturday morning, I went for a five mile test ride and realized I needed gloves, which necessitated a trip to Austin Tri-Cyclist, where I was not the only one making such a purchase :-). I was still a bit concerned about the swim, but I had a wetsuit, so I figured I'd done all I could do. Still, I was coveting one with sleeves... I next headed over to the Travis County Expo Center to pick up my swag bag, drop off my bicycle and gear, and check out the transition areas. Our happy faces before we get out of the car into the cold... Next morning, three of us drove out together and arrived in the cold dark of the Travis County Expo. Center at around 5:30. Did I mention that it was cold? Eventually, we got on the bus to take us to the staging area at Walter Long (Decker) Lake. There, we put on wetsuits, met up with our other training partners, and shivered a lot. Eventually, though, as the sun started to peak above the horizon, we lined up according to our projected swim times and prepared for the start of the race. I was still worried about the swim and the cold -- even though I was wearing socks (to be discarded just before start), my feet were starting to go numb and my arms were not happy either. But then it was time! I ran into the water and dived in as soon as I could. To my surprise, it was actually pleasant -- the water itself was around 68-72 degrees, so compared to the air temperature, it was balmy. The only real problem was that fog on the water and the glare of the sun were making it hard to see the buoys. About halfway through the swim I began thinking that the temperature really wasn't bad -- if anything, it was a bit too warm. Emerging from the water... But then I finished the swim and stood and was confronted by the reality of confronting an air temp of around 40 while being soaking wet. I grabbed my glasses from the special needs table and a nice man helped me get the wetsuit off. (This basically involved lying back on the wet ground, sticking my feet in the air and having him pull. Thank you, sir.). My time was a little slower than I would've liked, but I was fairly happy with it. I made it to transition, took a big swig of water, swallowed the contents of an energy gel pack, and put on my winter cycling garb. Then I was off! And it was frickin' cold. Contemplating that wind chill... It was this weird Catch-22 where you want to go as fast as possible (for the race, of course, but also so you warm up), but also kind of are thinking that if you slowed down a touch the wind chill wouldn't be quite so bad. I ended up spending the next hour shivering until the ambient temperature and I warmed up. Now, I actually kind of like the bike route -- it's mostly country roads with little traffic, and I rode the route about a half-dozen times in training. The problem with it is that a number of the roads are not exactly well=paved. Bumps and potholes and patches proliferate, especially on Monkey Road. In fact, the dip where it crosses a creek is so bumpy that by the time I got there, there were at least a dozen water bottle scattered on the ground. There were way too many hills, however :-). Beyond that, the ride felt fine, although my back began to hurt about halfway through -- I wasn't used to spending that much time in the aero position, so most of the second half of my ride was with hands on the brake hoods. I made sure to stick with my hydration and nutrition plan, so I felt pretty good by the end of it. Again, my time wasn't quite what I wanted it to be, but I was not displeased. By the time I finished the ride, it was around noon and fairly warm, so I took the time to change from my sleeved singlet to a sleeveless one (Ironman rules require that you wear a shirt). Starting to feel the legs... The run wasn't as bad as I thought it would be, although there were again too many hills :-). I was pleased at the number and size of the aid stations -- water, electrolyte drink (Gatorade, iirc), Clif energy gels, Coca-Cola, and Red Bull were all available. I was definitely feeling my legs, but my quads didn't feel like they were going to seize up like they had when I did triathlons in the 90s -- all that training paid off, I guess :-). I managed to make it through without slowing to a walk (other than at aid stations, because I can't drink and run at the same time) and ended up with a run time that was comparable to my stand-alone half-marathon times. At the finish line! My final time was 5:50:36, which I'm pretty happy about. My goal had been 6:00:00, although I did think that 5:45:00 was not out of the question. :-). Finisher photo! And medal! The gang... All in all, it was a great experience. I got out of my comfort zone, made some terrific friends, learned how to most efficiently change a bike tube, and never once thought, "I can't believe I'm paying to do this." (Okay, maybe once...). After the race! Celebrating the next day with Coach Peri! Full Article 70.3 Ironman races triathlon
w To the Moon, Mars, and beyond with the 2024 NASA Authorization By www.planetary.org Published On :: Fri, 12 Jul 2024 10:27:00 -0700 If passed, it would be the first standalone NASA authorization since 2017. Full Article
w How soon will Starship fly? By www.planetary.org Published On :: Mon, 15 Jul 2024 16:17:00 -0700 One rocket could decide how soon humanity returns to the Moon — and maybe one day sets foot on Mars. Full Article
w Why does Jupiter spin so fast? By www.planetary.org Published On :: Thu, 25 Jul 2024 07:00:00 -0700 The gas giant is the Solar System's largest planet. Here's why it's also the fastest-spinning planet. Full Article
w NASA discovers Mars rock with ancient potential for life By www.planetary.org Published On :: Thu, 01 Aug 2024 09:00:00 -0700 A single 3.5 billion-year-old rock shows signs of all the conditions life needs to thrive. Full Article
w How EELS could change the future of robotic exploration By www.planetary.org Published On :: Thu, 08 Aug 2024 07:00:00 -0700 The snake-like robot is being designed to autonomously navigate the challenging terrain of Saturn’s moon Enceladus, including descending into fissures in the moon’s icy crust. The skills it needs in order to explore this distant, unfamiliar world may make EELS well equipped to explore even more alien worlds, perhaps including exoplanets. Full Article
w Mars may host oceans’ worth of water deep underground By www.planetary.org Published On :: Mon, 12 Aug 2024 12:00:00 -0700 The tentative discovery hints at an habitat where life could potentially thrive. Full Article
w Why NASA does space science and not the private sector By www.planetary.org Published On :: Tue, 13 Aug 2024 08:00:00 -0700 With all the advances in private space exploration, why do taxpayers still pay for space science missions? Full Article
w Life in other worlds By www.planetary.org Published On :: Fri, 16 Aug 2024 07:30:00 -0700 New research suggests liquid water might be hiding under the surface of Mars. Could life be there too? Full Article
w What would happen if we nuked an asteroid? By www.planetary.org Published On :: Tue, 20 Aug 2024 07:00:00 -0700 Detonating a nuclear weapon on or near an asteroid is one of several options for defending the Earth from an impact. Here's what nuking an asteroid might actually do, and why it isn't always the best option. Full Article
w Ramses: A new mission racing to land on asteroid Apophis By www.planetary.org Published On :: Thu, 22 Aug 2024 07:00:00 -0700 When a skyscraper-sized asteroid narrowly misses Earth in 2029, three spacecraft may be along for the ride. Full Article
w Wow! Boom! Ultra cool! By www.planetary.org Published On :: Fri, 23 Aug 2024 07:30:00 -0700 The “Wow!" signal has a new explanation, and an ultra-cool experiment advances quantum sensing in space. Plus, making an asteroid go “boom!” might work, depending on the circumstances. Full Article
w Why the “habitable zone” doesn’t always mean habitable By www.planetary.org Published On :: Fri, 30 Aug 2024 08:03:00 -0700 The habitable zone is a useful concept in astrobiology, but it can sometimes paint an over-simplified picture of planetary habitability. Full Article
w Explore the Cosmos with The Planetary Society and Lerner Publishing By www.planetary.org Published On :: Fri, 30 Aug 2024 08:56:00 -0700 The Planetary Society and Lerner Publishing Group have teamed up to bring young readers an engaging series of books that make space science fun and accessible. Full Article
w Inside, underneath, backward, upside-down By www.planetary.org Published On :: Fri, 06 Sep 2024 07:30:00 -0700 From holes on Mars to a spun-around moon and a flipped reflection, space science involves looking at things from all different angles. Full Article
w Connecting ancient life to other worlds By www.planetary.org Published On :: Mon, 09 Sep 2024 06:57:00 -0700 Looking to the past to guide the search for life. Full Article
w New insights into asteroid properties: A STEP Grant update By www.planetary.org Published On :: Fri, 13 Sep 2024 07:00:00 -0700 A Planetary Society-funded project to understand asteroids achieved its main goals and scientific objectives this year. Full Article
w The Europa Clipper launch: What to expect By www.planetary.org Published On :: Thu, 19 Sep 2024 07:00:00 -0700 NASA is preparing to launch its flagship mission to explore Jupiter’s moon Europa. Launching sometime in October 2024 and arriving in 2030, the mission will explore the icy world with a subsurface ocean that scientists think could have conditions favorable to life. Full Article
w Spacecraft, what do your robot eyes see? By www.planetary.org Published On :: Fri, 20 Sep 2024 07:30:00 -0700 Cameras on spacecraft are our eyes into the Cosmos. Sometimes they teach us things, sometimes they reveal gaps in our knowledge. Full Article
w Where Congress Stands on NASA's 2025 budget By www.planetary.org Published On :: Fri, 20 Sep 2024 07:30:00 -0700 Weeks before the new fiscal year, Congress still hasn't finalized NASA's 2025 budget. Full Article
w The Hera launch: What to expect By www.planetary.org Published On :: Thu, 26 Sep 2024 07:00:00 -0700 The European Space Agency (ESA) is preparing to launch a mission to study the aftermath of DART's impact on the asteroid moonlet Dimorphos. Full Article
w How to spot Comet Tsuchinshan-Atlas By www.planetary.org Published On :: Thu, 26 Sep 2024 09:44:00 -0700 Catch this once-in-a-lifetime comet over the next few days. Full Article
w Glitter and glow By www.planetary.org Published On :: Fri, 04 Oct 2024 07:30:00 -0700 This week we look forward to launches, gaze at glowing auroras, and get creative with glitter. Full Article
w Twinsies! By www.planetary.org Published On :: Fri, 11 Oct 2024 07:30:00 -0700 Asteroids that come in pairs, matching volcanic features on Mars and Earth, and the potential space policies of two administrations. Full Article
w Solar maximum = maximum awe By www.planetary.org Published On :: Fri, 18 Oct 2024 07:30:00 -0700 With the Sun at the peak of its activity cycle, we Earthlings get treated to some awesome sights. Plus, some truly awe-inspiring launches happened this week. Full Article
w Journeys worth making By www.planetary.org Published On :: Fri, 01 Nov 2024 07:30:00 -0700 Perseverance faces a hard climb, but New Horizons proves it’s worth going the distance. Full Article
w Why Taylor-Serrano deserves top billing over Tyson-Paul carnival By www.bbc.com Published On :: Wed, 13 Nov 2024 08:10:57 GMT How the inclusion of Katie Taylor v Amanda Serrano on the bill legitimises the carnival of Mike Tyson v Jake Paul in Texas Full Article
w Barbour Nimbus Wellington Boots By uncrate.com Published On :: Tue, 12 Nov 2024 12:00:00 -0500 Full Article Shoes
w The James Brand × Timex Automatic GMT Watch By uncrate.com Published On :: Tue, 12 Nov 2024 12:18:54 -0500 Full Article Watches
w D1 Milano Polychrono Watch By uncrate.com Published On :: Tue, 12 Nov 2024 13:00:00 -0500 Full Article Watches
w Vollebak Eiderdown Puffer Jacket By uncrate.com Published On :: Tue, 12 Nov 2024 14:20:58 -0500 Full Article Outerwear
w Glenmorangie A Tale of Ice Cream Single Malt Scotch Whisky By uncrate.com Published On :: Tue, 12 Nov 2024 15:00:01 -0500 Full Article Whiskey
w YUKA 2000 Robot Lawn Mower By uncrate.com Published On :: Tue, 12 Nov 2024 18:00:00 -0500 Full Article Outdoor
w Christmas jewelry in progress. By maryannemohanraj.com Published On :: Sat, 09 Nov 2024 21:02:00 +0000 Sneak peek — Christmas jewelry in progress. Full Article Berwyn Shops Serendib House
w Starry Woods and Tardigrades! By maryannemohanraj.com Published On :: Sun, 10 Nov 2024 17:26:00 +0000 New in the shop — Starry Woods and Tardigrades! scarves. Full Article Berwyn Shops Serendib House
w One of my favorite native flowers By maryannemohanraj.com Published On :: Mon, 11 Nov 2024 00:55:00 +0000 Native wine-cups (aka purple poppy mallow) bookends. This is one of my favorite native flower, so particularly pleased with how nicely it shows up in bookends. Full Article Berwyn Shops Serendib House
w Learned something new By maryannemohanraj.com Published On :: Mon, 11 Nov 2024 13:59:00 +0000 Learned something new today— resin fidget spinner. ???? Full Article Uncategorized
w War for Cybertron game By iron-mitten.blogspot.com Published On :: Tue, 24 Sep 2024 18:20:00 +0000 The new Deception medic 'Wrench' gets his first taste of combat. I love this little cassette bot, he's so cute. I must make some more.Skyfire brings the rain. Full Article War for Cybertron War for Cybertron.
w Lake Town and Beorn By iron-mitten.blogspot.com Published On :: Thu, 26 Sep 2024 23:33:00 +0000 I've been messing around adding to the bear to days and trying not to rush myself. I'm so desperate to get some paint on it that I almost started today. However, I stopped myself and just added a bit more fur. This time I also ad buyded some to the bears face and now I'm finally happy with it.Cheeky!Some more help turns up to bolster Lake town and just in the nick of time.Two of these bases are really shoddy militia types. Pitch forks are a great short hand for 'rabble'. I can't imagine they will hold for long against the goblin horde.Another hero base .I think he looks angry, ragged and damn right mean now...let's get him painted up.I've added hints of blue so the whole force will tie together. The men start to suffer from the fierce wolf packs.The men with their long swords and the tough veterans from the Iron hills. Full Article lord Of The Rings lord Of The Rings.
w Dark Age Irish Warband By iron-mitten.blogspot.com Published On :: Fri, 27 Sep 2024 23:31:00 +0000 This is me working out my warband for a Dark age campaign. I can't really get going on it until I have finished my Hobbit armies for an up coming show. So In the meantime time this sketch of the warband will have to do. Out of the hat I got the Black shield Irish.The rules will be One hour wargames, and it's interesting to see the small size of the warband. Then again it is a skirmish game. Full Article Dark Ages
w Dwarf King in the shield wall By iron-mitten.blogspot.com Published On :: Sat, 05 Oct 2024 21:00:00 +0000 A Dwarf king and his elite guard take to the field. Amongst the Eagle helms of the shield wall is the kings champion himself. Nothing must get to the king and the champions blue axe, will see that nothing does.I could use this base for King Balin when he tries to retake Moria. A future project of mine.The King points out floors in the enemies formation to the chief engineer.The Dragon standard flies over head echoing the Kings mighty dragon helm.This base has been created for the upcoming Hobbit battle, replacing Dain's base in the ranks. This allows Dain to roam freely as a character on the field. The figures are beautiful old sculpts from Asgard and Citadel. There has been a bit of tweaking on a couple of them, like the axe and the standard. Full Article lord Of The Rings lord Of The Rings.
w FIW using Bonnie Blue Flag Rules By iron-mitten.blogspot.com Published On :: Wed, 30 Oct 2024 12:56:00 +0000 Here are the craziest scribblings of a madman. Having selected BBF for my black powder games, I'm now just trying to down scale it for a skirmish type game. Smaller units but still using multi bases for figures. Units of four seem to work as a base number. Here are the unit sizes in Muskets and Tomahawks that are good to see as a guide. All just early days still just throwing ideas around to see if something sticks.Drilled Vs irregular base.Update: Right! I've bit the bullet and revised my Indians for the game.I decided to go with 60x60mm bases to give a more spread out look. Also these Galloping Major figures are quite large for 28mm so it suits them better.I imagine four bases of Indians to a unit with a base of skirmishers. I just want one rule set for my black powder games and I think BBF is the one, with a few tweaks of course.My latest thinking is make Indians 'green', so they won't stick around long once the casualties start to mount up. A +10 melee modifier makes them dangerous close up so it's worth trying to get them into hand to hand. They are just too wise to stick around when things go bad. An experienced unit of warriors would be quite imposing with their combat bonus, something to be feared.I had thought of giving Rangers the same combat bonus but as they will be veterans, a plus 10 would be too much. I think let's class them as Elites with a +5. Full Article Bonnie Blue Flag
w War of the Roses Basing By iron-mitten.blogspot.com Published On :: Mon, 11 Nov 2024 21:44:00 +0000 The men of Lord Hastings' Retinue struggle through the mud of Tewkesbury.Vallejo thick mud was the perfect solution for the grim battle conditions of the war. Adding snow to this layer would look fantastic but would rather limit the battles. I think a generic muddy field is a good all rounder for this brutal conflict.I broke my usual 69x60mm basing after seeing a friend's and decided to copy it. Partly because the cheapness of plastics allows for bigger units. I also have quite a few old Perry miniatures from the old days of Foundry. These old lead figures are great for sprinkling amongst the ranks to add character. The above photo shows the effect of these old sculpts. They have to be mounted on plastic bases etc to bring them up to the height of the newer plastics. The mud is great for covering these and making everyone level.As the Vallejo mud was drying, I cut up some thin brush bristles and pushed them into the mixture. These make for great arrows and really helps to give the bases a War of the Roses look and feel.The mud is also great for splashing up the legs and clothes of the soldiers. It's quite subtle but helps to set them in the scene.The mud isn't quite dry yet and there are a couple more things to do before they are finished. Layers of 'Rutted field' from Luke's APS should look good over the mud, as well as patches of static grass. Also the arrows will need some white goose fletching on them. These new bases are 80x60mm and give a more realistic look to a unit. I got a bit carried away with these bases and they grew to 10 men per base.The figures In these units are a mix of old Foundry, Perry's plastics and Forlorn Hope metal figures. They all mix together well and make for characterful formations. Full Article War of the Roses
w Eugene Zaikonnikov: Breaking the Kernighan's Law By blog.funcall.org Published On :: Sun, 15 Sep 2024 15:00:00 GMT "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.." — Brian W. Kernighan. I'm a sucker for sage advice much as anyone else, and Kernighan is certainly right on money in the epigraph. Alas there comes a time in programmer's career when you just end up there despite the warning. It could be that you were indeed too clever for your own good, or maybe the code isn't quite yours anymore after each of your colleague's take on it over the years. Or just sometimes, the problem is indeed so hard that it strains your capacity as a coder. It would usually start with a reasonable idea made into first iteration code. The solution looks fundamentally sound but then as you explore the problem space further it begins to seep nuance, either as manifestation of some real world complexity or your lack of foresight. When I run into this my first instinct is to instrument the code. If the problem is formidable you got to respect it: flailing around blindly modifying things or ugh, doing a rewrite at this stage is almost guaranteed to be a waste of time. It helps to find a promising spot, chisel it, gain a foothold in the problem, and repeat until you crack it. Comfortable debugging tools here can really help to erode the original Kernighan coefficient from 2 to maybe 1.6 or 1.4 where you can still have a chance. Lisp users are fortunate with the options of interactive debugging, and one facility I reach often for is the plain BREAK. It's easy enough to wrap it into a conditional for particular matches you want to debug. However sometimes you want it to trigger after a particular sequence of events across different positions in code has taken place. While still doable it quickly becomes cumbersome and this state machine starts to occupy too much mental space which is already scarce. So one day, partly as a displacement activity from being intimidated by a Really Hard Problem I wrote down my debugging patterns as a handful of macros. Enter BRAKE. Its features reflect my personal preferences so are not necessarily your cup of tea but it could be a starting point to explore in this direction. Things it can do: act as a simple BREAK with no arguments (duh) wrap an s-expression, passing through its values upon continuing trigger sequentially based on the specified position for a common tag allow for marks that don't trigger the break but mark the position as reached provide conditional versions for the expressions above print traces of tagged breakpoints/marks If you compile functions with debug on you hopefully should be able to see the wrapped sexpr's result values. (use-package '(brake)) (defun fizzbuzz () (loop for n from 100 downto 0 for fizz = (zerop (mod n 3)) for buzz = (zerop (mod n 5)) do (format t "~a " (if (not (or fizz buzz)) (format nil "~d" n) (brake-when (= n 0) (concatenate 'string (if fizz "Fizz" "") (if buzz "Buzz" ""))))))) These macros try to detect common cases for tagged sequences being either aborted via break or completed to the last step, resetting them after to the initial state. However it is possible for a sequence to end up "abandoned", which can be cleaned up by a manual command. Say in the example below we want to break when the two first branches were triggered in a specific order. The sequence of 1, 3, 4 will reinitialize once the state 4 is reached, allowing to trigger continuously. At the same time if we blow our stack it should reset to initial when aborting. (defun ack (m n) (cond ((zerop m) (mark :ack 3 (1+ n))) ((zerop n) (mark :ack 1 (ack (1- m) 1))) (t (brake :ack 4 (ack (1- m) (ack m (1- n))))))) In addition there are a few utility functions to report on the state of brakepoints, enable or disable brakes based on tags and turn tracing on or off. Tracing isn't meant to replace the semantics of TRACE but to provide a souped up version of debug by print statements everyone loves. CL-USER> (report-brakes) Tag :M is DISABLED, traced, with 3 defined steps, current state is initial Tag :F is DISABLED with 2 defined steps, current state is 0 Tag :ACK is ENABLED with 3 defined steps, current state is initial Disabling breakpoints without recompilation is really handy and something I find using all the time. The ability to wrap a sexpr was often sorely missed when using BREAK in constructs without implicit body. Sequencing across threads is sketchy as the code isn't guarded but in many cases it can work, and the appeal of it in debugging races is clear. One of those days I hope to make it more robust while avoiding potential deadlocks but it isn't there yet. Where it already shines tho is in debugging complex iterations, mutually recursive functions and state machines. Full Article
w Patrick Stein: Ray Tracing In One Weekend (in Lisp, and n-dimenions) By nklein.com Published On :: Fri, 27 Sep 2024 02:37:31 GMT Earlier this year, I started working through the online book Ray Tracing In One Weekend (Book 1). I have been following along with it in Common Lisp, and I have been extending it all from 3-dimensional to n-dimensional. I reproduced 4-dimensional versions of all of the book images which you can see on my weekend-raytracer github page. Here is the final image. This is a 250-samples-per-pixel, 640x360x10 image plane of three large hyperspheres (one mirrored, one diffuse, one glass) atop a very large, diffuse hypersphere. Also atop this very large hypersphere are a bunch of smaller hyperspheres of varying colors and materials. The image is rendered with some defocus-blur. Final image of 4-dimensional scene Caveat: This depends on a patched version of the policy-cond library that is not in the current Quicklisp distribution but should be in the next. Full Article
w Quicklisp news: October 2024 Quicklisp dist update now available By blog.quicklisp.org Published On :: Tue, 15 Oct 2024 20:16:00 GMT New projects: adp-github — ADP extension to generate github markdown files. — MITadp-plain — Add Documentation, Please... using plain text. An extension of ADP to generate files with barely additional features. — MITallioli — Alliolification — MITalternate-asdf-system-connections — Allows for ASDF system to be connected so that auto-loading may occur. This is a fork of asdf-system-connections and incorporates a load-system-driven mechanism for loading dependencies and also loads the dependencies of the connections. — MITcbor — CBOR encoder/decoder — MITcharje.documentation — Documentation is an opinionated yet customizable docstring parsing library. — AGPL V3 or any later versionchipi — House automation bus in Common Lisp — Apache-2cl-aseprite — Aseprite file format parser — GPLv3cl-astar — A heavily optimized yet flexible A* pathfinding algorithm implementation — MITcl-ceigen-lite — A Common Lisp wrapper around CEIGEN-LITE - which is itself a C wrapper around the C++ Eigen library. — MITcl-cf — Computations using continued fractions — GPL-3cl-concord — CONCORD implementation based on Common Lisp — LGPLcl-duckdb — CFFI wrapper around the DuckDB C API — MIT Licensecl-fastcgi — FastCGI wrapper for Common Lisp — BSD Licensecl-flx — Rewrite emacs-flx in Common Lisp — MITcl-frugal-uuid — Common Lisp UUID library with zero dependencies — MIT Licensecl-gog-galaxy — A wrapper for the GOG Galaxy SDK — zlibcl-lc — List comprehensions — MITcl-naive-ptrees — Functions to make it easier to work with plist(s) and plist trees. Works with plist(s) pairs as units and not as individual list items. — MITcl-qoa — An implementation of the Quite Okay Audio format. — zlibcl-reddit — Reddit client api library — BSDcl-resvg — An up-to-date bindings library for the resvg SVG rendering library — zlibcl-trivial-clock — Common Lisp library to get accurate wall-clock times on multiple platforms — MIT Licenseclack-cors — A Clack middleware to set CORS related HTTP headers. — Unlicenseclack-prometheus — Clack middleware to serve stats in Prometheus format. — Unlicenseclith — Common Lisp wITH macro. A general WITH macro. — MITclj-arrows — Implements Clojure-styled threading/transformation macros. — MITclos-encounters — A collection of OOP patterns benefiting from the CLOS MOP. — Unlicensecoalton — An efficient, statically typed functional programming language that supercharges Common Lisp. — MITcocoas — A toolkit library to help deal with CoreFoundation, Cocoa, and objc — zlibcom.danielkeogh.graph — A fast an reliable graph library. — MITfast-mpsc-queue — Multi-Producer Single-Consumer queue implementation. — MITfile-finder — File finder. Enable rapid file search, inspection and manipulation. — GPL3+golden-utils — A utility library. — MIThiccl — HTML generator for Common Lisp — MIThsx — Hypertext S-expression — MIThunchentoot-stuck-connection-monitor — Monitors hunchentoot connections and logs the connections stuck in the same state for a long time (due to slow or inactive clients and network stream timeouts that hunchentoot tries to utilize not working properly). Offers an option to shutdown the stuck connections sockets manually or automatically, thus unblocking the connection threads and preventing thread and socket leak. See https://github.com/edicl/hunchentoot/issues/189 — BSD-2-Clauseincless — A portable and extensible Common Lisp printer implementation (core) — BSDinravina — A portable and extensible Common Lisp pretty printer. — MITinvistra — A portable and extensible Common Lisp FORMAT implementation — BSDknx-conn — KNXnet/IP implementation in Common Lisp — GNU GPL, version 3machine-state — Retrieve machine state information about CPU time, memory usage, etc. — zlibmyweb — simple web server written in common lisp for educational reasons — LGPLv3noisy — Perlin noise for arbitrary numbers of dimensions. — MITnontrivial-gray-streams — A compatibility layer for Gray streams including extensions — MITopen-with — Open a file in a suitable external program — zlibopenai-openapi-client — Openai API client — AGPLv3+openrpc — CI for Common Lisp OpenRPC library. — BSDparse-number-range — Parses LOOP's convenient "for-as-arithmetic" syntax into 5 simple values: from, to, limit-kind (:inclusive, :exclusive or nil if unbounded), by (step) and direction (+ or -)). Further related utilities are provided. Intended for easy implementation of analogous functionality in other constructs. — Public Domainprecise-time — Precise time measurements — zlibpregexp — Portable regular expressions for Common Lisp — MIT-likeprogressons — Display a progress bar on one line. — MITquaviver — A portable and extensible floating point string library — MITquilc — A CLI front-end for the Quil compiler — Apache License 2.0 (See LICENSE.txt)qvm — An implementation of the Quantum Abstract Machine. — Apache License 2.0 (See LICENSE.txt)random-sampling — Functions to generate random samples with various distributions — zlibrs-dlx — Knuth's Algorithm X with dancing links. — Modified BSD Licensescrapycl — The web scraping framework for writing crawlers in Common Lisp. — Unlicensesmoothers — Statistical methods to create approximating functions that attempt to capture important patterns in the data, while leaving out noise or other fine-scale structures/rapid phenomena. — MS-PLtrivial-adjust-simple-array — A tiny utility to change array size ensuring it is simple. — MITtrivial-system-loader — A system installation/loading abstraction for Common Lisp — MITtrivial-toplevel-commands — Trivial Toplevel Commands allows to define toplevel commands available on most implementations in a portable fashion. — BSD-3 Clausetrivial-toplevel-prompt — Portability library to customize REPL prompts. — BSD-3 Clauseutf8-input-stream — A UTF-8 string input stream over a binary stream for Common Lisp — MITwhereiseveryone.command-line-args — Automatically create a command-line-argument parser for a given Common Lisp function definition. — AGPL v3 or any later versionUpdated projects: 3b-bmfont, 3bgl-shader, 3bmd, 3d-math, 3d-spaces, 40ants-asdf-system, 40ants-slynk, access, acclimation, action-list, adhoc, adopt, adp, agnostic-lizard, alexandria, alexandria-plus, anatevka, anypool, april, arc-compat, architecture.builder-protocol, array-utils, arrow-macros, assoc-utils, async-process, atomics, auto-restart, aws-sdk-lisp, babel, bdef, bike, binary-structures, binding-arrows, birch, blackbird, bordeaux-threads, calm, carrier, caveman, ccldoc, cephes.cl, cepl, cerberus, cffi, cffi-object, cffi-ops, chanl, chunga, ci, ci-utils, ciao, cl-6502, cl-algebraic-data-type, cl-all, cl-ansi-term, cl-async, cl-atelier, cl-autowrap, cl-base32, cl-bmas, cl-bmp, cl-bnf, cl-brewer, cl-buchberger, cl-cmark, cl-collider, cl-colors2, cl-confidence, cl-containers, cl-cookie, cl-csv, cl-custom-hash-table, cl-cxx-jit, cl-data-structures, cl-dbi, cl-digraph, cl-dot, cl-enchant, cl-environments, cl-fast-ecs, cl-fbx, cl-fluent-logger, cl-form-types, cl-forms, cl-freetype2, cl-gamepad, cl-github-v3, cl-gltf, cl-gobject-introspection, cl-graph, cl-grip, cl-gserver, cl-hamcrest, cl-hash-util, cl-html-readme, cl-i18n, cl-info, cl-ini, cl-ipfs-api2, cl-kanren, cl-lib-helper, cl-liballegro, cl-liballegro-nuklear, cl-log, cl-markless, cl-marshal, cl-migratum, cl-mixed, cl-modio, cl-mount-info, cl-mpg123, cl-mssql, cl-mustache, cl-mysql, cl-neovim, cl-netpbm, cl-oju, cl-opengl, cl-opensearch-query-builder, cl-opus, cl-patterns, cl-plus-ssl-osx-fix, cl-ppcre, cl-project, cl-protobufs, cl-pslib, cl-pslib-barcode, cl-rashell, cl-readline, cl-sat.minisat, cl-sdl2-image, cl-sdl2-mixer, cl-sdl2-ttf, cl-sendgrid, cl-sentry-client, cl-skkserv, cl-smtp, cl-ssh-keys, cl-steamworks, cl-str, cl-svg, cl-telegram-bot, cl-threadpool, cl-tiled, cl-torrents, cl-tqdm, cl-transducers, cl-transit, cl-unicode, cl-unification, cl-unix-sockets, cl-utils, cl-vectors, cl-vorbis, cl-wavefront, cl-webdriver-client, cl-webkit, cl-webmachine, cl-who, clack, clack-pretend, clad, classimp, clast, clath, clavier, clazy, clerk, clgplot, climacs, clingon, clip, clj-con, clj-re, clobber, clog, clog-ace, clog-collection, clog-plotly, clog-terminal, clohost, closer-mop, clss, cluffer, clunit2, clx, cmd, codata-recommended-values, codex, coleslaw, collectors, colored, com-on, common-lisp-jupyter, commondoc-markdown, compiler-macro-notes, conduit-packages, consfigurator, contextl, croatoan, ctype, cytoscape-clj, damn-fast-priority-queue, dartscluuid, data-frame, data-lens, datafly, dbus, decompress, defenum, definer, definitions, deflate, defmain, deploy, depot, deptree, dexador, dissect, djula, dns-client, doc, docs-builder, dsm, dufy, easter-gauss, easy-audio, easy-macros, easy-routes, eclector, equals, erjoalgo-webutil, erudite, esrap, event-emitter, external-program, external-symbol-not-found, fare-csv, fare-scripts, fast-http, fast-websocket, file-attributes, file-notify, file-select, filesystem-utils, fiveam, fiveam-matchers, flexi-streams, float-features, flow, fn, fset, functional-trees, fuzzy-dates, gadgets, generic-cl, github-api-cl, glfw, glsl-toolkit, harmony, hashtrie, helambdap, http2, hunchentoot, imago, in-nomine, inferior-shell, introspect-environment, ironclad, jose, js, json-mop, jsonrpc, jzon, khazern, lack, lass, lemmy-api, letv, lichat-protocol, lichat-tcp-client, linear-programming, lisp-binary, lisp-chat, lisp-critic, lisp-pay, lisp-stat, lispcord, lla, local-time, log4cl-extras, logging, lru-cache, magicl, maiden, maidenhead, manifolds, math, mcclim, memory-regions, messagebox, method-combination-utilities, mgl-pax, misc-extensions, mito, mk-defsystem, mmap, mnas-package, mnas-string, moira, multiposter, mutility, mutils, named-closure, ndebug, neural-classifier, new-op, nibbles, nibbles-streams, ningle, nodgui, north, numerical-utilities, nytpu.lisp-utils, omglib, ook, open-location-code, openapi-generator, orizuru-orm, overlord, papyrus, parachute, parse-number, pathname-utils, petalisp, phos, picl, plot, plump, plump-sexp, pngload, policy-cond, polymorphic-functions, postmodern, ppath, prometheus-gc, psychiq, purgatory, py4cl, py4cl2, py4cl2-cffi, qlot, qoi, query-fs, quick-patch, quickhull, quri, random-state, reblocks, reblocks-auth, reblocks-file-server, reblocks-lass, reblocks-navigation-widget, reblocks-parenscript, reblocks-prometheus, reblocks-typeahead, reblocks-ui, reblocks-websocket, rove, s-dot2, sandalphon.lambda-list, sb-fastcgi, sc-extensions, sel, select, serapeum, shasht, shop3, si-kanren, sketch, slime, slite, sly, snooze, spinneret, staple, static-vectors, statistics, stepster, stmx, stripe, swank-crew, swank-protocol, sxql, symath, system-locale, taglib, teddy, ten, testiere, tfeb-lisp-hax, tfm, tiny-routes, tooter, trivia, trivial-arguments, trivial-clipboard, trivial-file-size, trivial-gray-streams, trivial-main-thread, trivial-octet-streams, trivial-package-locks, trivial-package-manager, trivial-sanitize, trivial-shell, type-templates, typo, uax-15, uiop, usocket, vellum, vellum-binary, vellum-csv, vellum-postmodern, verbose, vernacular, vom, websocket-driver, winhttp, with-branching, with-contexts, woo, xhtmlambda, xml-emitter, yason, zippy, zpb-ttf.Removed projects: abstract-arrays, ahungry-fleece, cl-cheshire-cat, cl-darksky, cl-epoch, cl-naive-store, convolution-kernel, dense-arrays, extensible-compound-types, extensible-optimizing-coerce, fast-generic-functions, flac-metadata, freebsd-ffi, listoflist, luckless, one-more-re-nightmare, postmodern-localtime, stumpwm-dynamic-float, stumpwm-sndioctl, unicly.To get this update, use: (ql:update-dist "quicklisp")Sorry this update took so long. My goal is to resume monthly releases.Enjoy! Full Article
w TurtleWare: Dynamic Vars - A New Hope By turtleware.eu Published On :: Tue, 22 Oct 2024 00:00:00 GMT Table of Contents Dynamic Bindings The problem The solution Dynamic slots The context Summary Dynamic Bindings Common Lisp has an important language feature called dynamic binding. It is possible to rebind a dynamic variable somewhere on the call stack and downstream functions will see that new value, and when the stack is unwound, the old value is brought back. While Common Lisp does not specify multi-threading, it seems to be a consensus among various implementations that dynamic bindings are thread-local, allowing for controlling the computing context in a safe way. Before we start experiments, let's define a package to isolate our namespace: (defpackage "EU.TURTLEWARE.BLOG/DLET" (:local-nicknames ("MOP" #+closer-mop "C2MOP" #+(and (not closer-mop) ecl) "MOP" #+(and (not closer-mop) ccl) "CCL" #+(and (not closer-mop) sbcl) "SB-MOP")) (:use "CL")) (in-package "EU.TURTLEWARE.BLOG/DLET") Dynamic binding of variables is transparent to the programmer, because the operator LET is used for both lexical and dynamic bindings. For example: (defvar *dynamic-variable* 42) (defun test () (let ((*dynamic-variable* 15) (lexical-variable 12)) (lambda () (print (cons *dynamic-variable* lexical-variable))))) (funcall (test)) ;;; (42 . 12) (let ((*dynamic-variable* 'xx)) (funcall (test))) ;;; (xx . 12) Additionally the language specifies a special operator PROGV that gives the programmer a control over the dynamic binding mechanism, by allowing passing the dynamic variable by value instead of its name. Dynamic variables are represented by symbols: (progv (list '*dynamic-variable*) (list 'zz) (funcall (test))) ;;; (zz . 12) The problem Nowadays it is common to encapsulate the state in the instance of a class. Sometimes that state is dynamic. It would be nice if we could use dynamic binding to control it. That said slots are not variables, and if there are many objects of the same class with different states, then using dynamic variables defined with DEFVAR is not feasible. Consider the following classes which we want to be thread-safe: (defgeneric call-with-ink (cont window ink)) (defclass window-1 () ((ink :initform 'red :accessor ink))) (defmethod call-with-ink (cont (win window-1) ink) (let ((old-ink (ink win))) (setf (ink win) ink) (unwind-protect (funcall cont) (setf (ink win) old-ink)))) (defclass window-2 () ()) (defvar *ink* 'blue) (defmethod ink ((window window-2)) *ink*) (defmethod call-with-ink (cont (win window-2) ink) (let ((*ink* ink)) (funcall cont))) The first example is clearly not thread safe. If we access the WINDOW-1 instance from multiple threads, then they will overwrite a value of the slot INK. The second example is not good either, because when we have many instances of WINDOW-2 then they share the binding. Nesting CALL-WITH-INK will overwrite the binding of another window. The solution The solution is to use PROGV: (defclass window-3 () ((ink :initform (gensym)))) (defmethod initialize-instance :after ((win window-3) &key) (setf (symbol-value (slot-value win 'ink)) 'red)) (defmethod call-with-ink (cont (win window-3) ink) (progv (list (slot-value win 'ink)) (list ink) (funcall cont))) This way each instance has its own dynamic variable that may be rebound with a designated operator CALL-WITH-INK. It is thread-safe and private. We may add some syntactic sugar so it is more similar to let: (defmacro dlet (bindings &body body) (loop for (var val) in bindings collect var into vars collect val into vals finally (return `(progv (list ,@vars) (list ,@vals) ,@body)))) (defmacro dset (&rest pairs) `(setf ,@(loop for (var val) on pairs by #'cddr collect `(symbol-value ,var) collect val))) (defmacro dref (variable) `(symbol-value ,variable)) Dynamic slots While meta-classes are not easily composable, it is worth noting that we can mold it better into the language by specifying that slot itself has a dynamic value. This way CLOS aficionados will have a new tool in their arsenal. The approach we'll take is that a fresh symbol is stored as the value of each instance-allocated slot, and then accessors for the slot value will use these symbols as a dynamic variable. Here are low-level accessors: ;;; Accessing and binding symbols behind the slot. We don't use SLOT-VALUE, ;;; because it will return the _value_ of the dynamic variable, and not the ;;; variable itself. (defun slot-dvar (object slotd) (mop:standard-instance-access object (mop:slot-definition-location slotd))) (defun slot-dvar* (object slot-name) (let* ((class (class-of object)) (slotd (find slot-name (mop:class-slots class) :key #'mop:slot-definition-name))) (slot-dvar object slotd))) (defmacro slot-dlet (bindings &body body) `(dlet ,(loop for ((object slot-name) val) in bindings collect `((slot-dvar* ,object ,slot-name) ,val)) ,@body)) Now we'll define the meta-class. We need that to specialize functions responsible for processing slot definitions and the instance allocation. Notice, that we make use of a kludge to communicate between COMPUTE-EFFECTIVE-SLOT-DEFINITION and EFFECTIVE-SLOT-DEFINITION-CLASS – this is because the latter has no access to the direct slot definitions. ;;; The metaclass CLASS-WITH-DYNAMIC-SLOTS specifies alternative effective slot ;;; definitions for slots with an initarg :dynamic. (defclass class-with-dynamic-slots (standard-class) ()) ;;; Class with dynamic slots may be subclasses of the standard class. (defmethod mop:validate-superclass ((class class-with-dynamic-slots) (super standard-class)) t) ;;; When allocating the instance we initialize all slots to a fresh symbol that ;;; represents the dynamic variable. (defmethod allocate-instance ((class class-with-dynamic-slots) &rest initargs) (declare (ignore initargs)) (let ((object (call-next-method))) (loop for slotd in (mop:class-slots class) when (typep slotd 'dynamic-effective-slot) do (setf (mop:standard-instance-access object (mop:slot-definition-location slotd)) (gensym (string (mop:slot-definition-name slotd))))) object)) ;;; To improve potential composability of CLASS-WITH-DYNAMIC-SLOTS with other ;;; metaclasses we treat specially only slots that has :DYNAMIC in initargs, ;;; otherwise we call the next method. (defmethod mop:direct-slot-definition-class ((class class-with-dynamic-slots) &rest initargs) (loop for (key val) on initargs by #'cddr when (eq key :dynamic) do (return-from mop:direct-slot-definition-class (find-class 'dynamic-direct-slot))) (call-next-method)) ;;; The metaobject protocol did not specify an elegant way to communicate ;;; between the direct slot definition and the effective slot definition. ;;; Luckily we have dynamic bindings! :-) (defvar *kludge/mop-deficiency/dynamic-slot-p* nil) (defmethod mop:compute-effective-slot-definition ((class class-with-dynamic-slots) name direct-slotds) (if (typep (first direct-slotds) 'dynamic-direct-slot) (let* ((*kludge/mop-deficiency/dynamic-slot-p* t)) (call-next-method)) (call-next-method))) (defmethod mop:effective-slot-definition-class ((class class-with-dynamic-slots) &rest initargs) (declare (ignore initargs)) (if *kludge/mop-deficiency/dynamic-slot-p* (find-class 'dynamic-effective-slot) (call-next-method))) Finally we define a direct and an effective slot classes, and specialize slot accessors that are invoked by the instance accessors. ;;; There is a considerable boilerplate involving customizing slots. ;;; ;;; - direct slot definition: local to a single defclass form ;;; ;;; - effective slot definition: combination of all direct slots with the same ;;; name in the class and its superclasses ;;; (defclass dynamic-direct-slot (mop:standard-direct-slot-definition) ((dynamic :initform nil :initarg :dynamic :reader dynamic-slot-p))) ;;; DYNAMIC-EFFECTIVE-SLOT is implemented to return as slot-value values of the ;;; dynamic variable that is stored with the instance. ;;; ;;; It would be nice if we could specify :ALLOCATION :DYNAMIC for the slot, but ;;; then STANDARD-INSTANCE-ACCESS would go belly up. We could make a clever ;;; workaround, but who cares? (defclass dynamic-effective-slot (mop:standard-effective-slot-definition) ()) (defmethod mop:slot-value-using-class ((class class-with-dynamic-slots) object (slotd dynamic-effective-slot)) (dref (slot-dvar object slotd))) (defmethod (setf mop:slot-value-using-class) (new-value (class class-with-dynamic-slots) object (slotd dynamic-effective-slot)) (dset (slot-dvar object slotd) new-value)) (defmethod mop:slot-boundp-using-class ((class class-with-dynamic-slots) object (slotd dynamic-effective-slot)) (boundp (slot-dvar object slotd))) (defmethod mop:slot-makunbound-using-class ((class class-with-dynamic-slots) object (slotd dynamic-effective-slot)) (makunbound (slot-dvar object slotd))) With this, we can finally define a class with slots that have dynamic values. What's more, we may bind them like dynamic variables. ;;; Let there be light. (defclass window-4 () ((ink :initform 'red :dynamic t :accessor ink) (normal :initform 'normal :accessor normal)) (:metaclass class-with-dynamic-slots)) (let ((object (make-instance 'window-4))) (slot-dlet (((object 'ink) 15)) (print (ink object))) (print (ink object))) ContextL provides a similar solution with dynamic slots, although it provides much more, like layered classes. This example is much more self-contained. The context Lately I'm working on the repaint queue for McCLIM. While doing so I've decided to make stream operations thread-safe, so it is possible to draw on the stream and write to it from arbitrary thread asynchronously. The access to the output record history needs to be clearly locked, so that may be solved by the mutex. Graphics state is another story, consider the following functions running from separate threads: (defun team-red () (with-drawing-options (stream :ink +dark-red+) (loop for i from 0 below 50000 do (write-string (format nil "XXX: ~5d~%" i) stream)))) (defun team-blue () (with-drawing-options (stream :ink +dark-blue+) (loop for i from 0 below 50000 do (write-string (format nil "YYY: ~5d~%" i) stream)))) (defun team-pink () (with-drawing-options (stream :ink +deep-pink+) (loop for i from 0 below 25000 do (case (random 2) (0 (draw-rectangle* stream 200 (* i 100) 250 (+ (* i 100) 50))) (1 (draw-circle* stream 225 (+ (* i 100) 25) 25)))))) (defun gonow (stream) (window-clear stream) (time (let ((a (clim-sys:make-process #'team-red)) (b (clim-sys:make-process #'team-blue)) (c (clim-sys:make-process #'team-grue))) (bt:join-thread a) (bt:join-thread b) (bt:join-thread c) (format stream "done!~%"))) ) Operations like WRITE-STRING and DRAW-RECTANGLE can be implemented by holding a lock over the shared resource without much disruption. The drawing color on the other hand is set outside of the loop, so if we had locked the graphics state with a lock, then these functions would be serialized despite being called from different processes. The solution to this problem is to make graphics context a dynamic slot that is accessed with WITH-DRAWING-OPTIONS. Summary I hope that I've convinced you that dynamic variables are cool (I'm sure that majority of readers here are already convinced), and that dynamic slots are even cooler :-). Watch forward to the upcoming McCLIM release! If you like technical writeups like this, please consider supporting me on Patreon. Full Article