Author Topic: Simon blogs  (Read 9153 times)

0 Members and 1 Guest are viewing this topic.

Offline ccexplore

  • Administrator
  • Posts: 4690
    • View Profile
Re: Simon blogs
« Reply #75 on: May 06, 2017, 10:05:09 am »
Incidentally, (temporary) switching of globals may not be that bad if you manage it through a RAII helper class whose purpose is basically to override the global for the duration of the lifetime of the helper class (and restoring to the previous value upon finalization).  Of course this assumes certain patterns usage such as no multithreading.

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #76 on: May 10, 2017, 03:47:38 pm »
Yes, I like RAII helpers in similar situations. I wrapped target bitmaps or blenders in them, these are Allegro thread-local.

Lix is entirely single-threaded. There is theoretical potential to parallelize: D has all mutable variables thread-local by default, Allegro 5 drawing routines have a global drawing target per thread. But multithreading is daunting and my early dabblings in 2015 to parallelize crashed.

In my application, the drawing context switches so rarely that I'd rather not clutter the GUI elements' interface. But enlarging that interface is a good solution in general.





Fruit basket problem

(Source: Object-Oriented Design Heuristics, by Arthur J. Riel)

You have a class Fruit, with subclasses Apple, Banana, Orange. In particular, Apples know how to core themselves. And there is a container class Basket, this collects Fruit and allows you to insert and iterate over the fruit. We have lots of different fruits in the basket. How do we iterate over the fruits, telling the Apples to core themselves, ignoring other types of fruit?

The Smalltalk solution is that you tell every fruit to core itself. Calling core on a Banana would be legal even if Banana doesn't understand this, and the banana would do nothing. (Wrong, see 2 posts further down.) The problem becomes much harder in D, C++, or Java; here, it's illegal to call core on Fruit. I like strict static analysis and want the compiler to yell at me.

Proposed solutions:

Fat interface: Make an empty method core in Fruit. Override this only in Apple with the meaningful behavior. Call core on every fruit in the Basket. Downside: Fruit gets special knowledge of Apple behavior. But maybe this is the least intrusive solution.

Explicit analysis: dynamic_cast<Apple*> every Fruit*. This returns null if we have a banana or orange. Call core on what casts successfully to Apple. Downsides: The fruit basket problem is far too common. Explicit case analysis everywhere is exactly what OOP tries to avoid. Instead of littering the entire codebase with special-casings, we should centralize all this special-casing in classes Fruit and Apple. We'd get OOP's verbosity without reaping its benefits.

Apple-knowing Basket: Consider Fruit and Apple correctly designed, but Basket ill-suited for our purpose. By definition, the Basket returns Fruit references, and calling core on Fruit is not allowed. Instead, the Basket should privately maintain a list of Fruit references, and, separately, a list of Apple references that point to the same objects as the Fruit list points to. Downsides: What is the Basket's interface to add elements? Will it dynamic-cast, or should Basket's caller make sure he calls addFruit and addApple correctly? What happens if Basket's caller gets their Fruit from a Fruit source that doesn't support this pattern?

-- Simon
« Last Edit: September 27, 2017, 08:36:07 pm by Simon »

Offline ccexplore

  • Administrator
  • Posts: 4690
    • View Profile
Re: Simon blogs
« Reply #77 on: May 10, 2017, 07:57:10 pm »
Hmm, apple-knowing baskets frankly sound like a hack that doesn't really scale all that better than explicit analysis or fat interface.  If peeling fruit becomes a thing (let's say for purpose of discussion, some fruits like strawberries can't be peeled, even though I'm guessing technically they probably still have some kind of peel in terms of biology), does the basket now also need to track that separately too?  What if I want to carry my fruits in a tray instead, does the tray now have to copy all the special-casing that the basket is doing?

How does Smalltalk handle the case where the method being called would normally return a value?  If you try to invoke the method on an object that doesn't actually support the method, what happens?  Does the invocation attempt still return some sort of default or special value (think null or undefined or similar) for that case?  It seems to me even in Smalltalk, you may not be able to always take advantage of the feature where it silently allows methods to be invoked on unsupported types.  Even if the language guarantees some sort of well-defined return value in the unsupported case, its semantics may not always be what you want for downstream calculations/processing utilizing the return value, and in such cases it could be better or even required to check for support-ness upfront instead.

Ultimately, regardless of language support, what ends up happening "under the hood" is that the check will be made one way or another, whether implicitly by the language (eg. Smalltalk would effectively be doing the check for you of whether the method exists for the target object) or explicitly by the programmer.  For languages where it must be done explicitly, it just becomes a matter of if/where/how you want to "hide" the check.

In some cases you can also simplify the manual checking by, for example, requiring fruits to implement an ICoreable interface if it supports coring.  So you just have to check for ICoreable and not more explicitly for specific fruit types.

I do agree that the situation you are describing [ie. abstracting out the pattern of "if (supported) dothis() else /* do nothing */"] is not uncommon, and it would probably be useful for commonly used languages to support that case better.

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #78 on: May 10, 2017, 08:34:24 pm »
Good reply, I googled some more.

Errata: Smalltalk won't let you call nonexistant methods on objects by default, that's a runtime exception. You could redefine the nonexistant-method handler in your classes, but that would be considered a massive hack.

Smalltalk lets you call existant methods on null references, and does nothing. This is much different and doesn't help with the fruit basket problem.

Will come back for the rest!

-- Simon

Offline Colorful Arty

  • Posts: 473
  • You are loved!
    • View Profile
    • Colorful Arty's Youtube Page
Re: Simon blogs
« Reply #79 on: May 10, 2017, 10:16:43 pm »
I like this scenario. My first instinct would be to create a boolean attribute for Fruit named isCoreable and then give the subclasses of fruit that are coreable the core() function. Then, you can check each fruit, check if its attribute isCoreable is true, then call the method core().

I know for sure this is not optimal, which is where you could have the subclasses of Fruit that are coreable implement an interface that lets them be cored. I'm not sure how many languages use interfaces, but Java does, and Python can use abstract classes instead to solve the problem.
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My levelpack: SubLems
For NeoLemmix: http://www.lemmingsforums.net/index.php?topic=2787.0
For SuperLemmini: http://www.lemmingsforums.net/index.php?topic=2704.0

Upcoming levelpack: ArtLems
Development Topic: http://www.lemmingsforums.net/index.php?topic=3166.0

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #80 on: May 10, 2017, 11:09:07 pm »
apple-knowing baskets frankly sound like a hack
need to track that [peeling] separately too?
carry my fruits in a tray instead, does the tray now have to copy all the special-casing that the basket is doing?

I assume the work grows too quickly here, yes.

I don't dare to propose a Basket<mainClass, subclass1, subclass2, ...> with compile-time code generation, even when that's probably possible. :lix-suspicious: Maybe this is truly the land for dynamic typing without any static checks at all? But even those raise errors on unsupported methods...

Quote
How does Smalltalk handle [...] still return some sort of default or special value (think null or undefined or similar) for that case?

Most of this is answered by "I erred and Smalltalk doesn't allow it by default." The Smalltalk nil object responds to all messages that the class would normally respond to, and returns the nil object. This looks OK because everything is an object in Smalltalk.

Quote
For languages where it must be done explicitly, it just becomes a matter of if/where/how you want to "hide" the check.

Wise interpretation. The three proposed suggestions happen give the three possible answers: The check can go in the element class, in the client code, or in the container class. I didn't see this! :lix-scared:

Quote
I do agree that the situation you are describing [ie. abstracting out the pattern of "if (supported) dothis() else /* do nothing */"] is not uncommon, and it would probably be useful for commonly used languages to support that case better.

Nnnnn, thanks. :lix-grin:

Quote from: Colorful Arty
create a boolean attribute for Fruit named isCoreable and then give the subclasses of fruit that are coreable the core() function. Then, you can check each fruit, check if its attribute isCoreable is true, then call the method core().

Yep, this looks like a variant of the fat interface. The Fruit class gets some Apple-specific knowledge.

If you define isCoreable in Fruit, and core() only in the subclasses, then you still have to cast in the client code.

Quote
subclasses of Fruit that are coreable implement an interface that lets them be cored. I'm not sure how many languages use interfaces, but Java does, and Python can use abstract classes instead to solve the problem.
Quote
In some cases you can also simplify the manual checking by, for example, requiring fruits to implement an ICoreable interface if it supports coring.  So you just have to check for ICoreable and not more explicitly for specific fruit types.

This is excellent when we don't like to put everything right in base class. The example becomes Banana : Fruit; Orange : Fruit; Apple : Fruit, Coreable.

Defining the Coreable interface is probably wise even if we do it solely for explicit dynamic casting later. Coring seems to be a central concern in our domain, otherwise we wouldn't worry as much about this particular design problem. We can well abstract that into an interface and dynamic-cast to that.



Bonus: Found a webpage with the exact section from Riel's book! I bought the hardcover second-hand last year, it was splendid bedtime reading. At least if you believe that OO is often good. :lix-laugh:

-- Simon
« Last Edit: May 10, 2017, 11:42:21 pm by Simon »

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #81 on: May 30, 2017, 11:15:54 am »
Root partition

Tips around the internet suggest about 20 GB for the root partition on a typical Linux home system. The root partition hosts the operating system, programs installed for all users, libraries, temporary files, ... almost anything except for your personal data.

20 GB is too little in 2017. Anything with multimedia is fat, even when it doesn't yet output files. A workable system is already 5 GB. The video codec suite ffmpeg together with CUDA and other dependencies easily eats 5 GB. Maybe the OS wants to store old packages for emergency downgrades, etc., another few GB. Latex with common packages is over 1 GB. Interested in programming projects in different languages? Several hundred MB for each environment with libraries and toolchain.

40 GB seems much more adequate. When you can fit a walrus on the root partition, it's adequately sized. I conjecture we need 80 GB in 2030, 160 GB in 2040, doubling every 10 years. When I'll be 85 years old, in 2070, let's check how accurate this guess was.



-- Simon
« Last Edit: May 30, 2017, 11:30:32 am by Simon »

Offline ccexplore

  • Administrator
  • Posts: 4690
    • View Profile
Re: Simon blogs
« Reply #82 on: May 30, 2017, 06:37:37 pm »
Not much familiarity with Linux, but the fact that apparently installed programs and libraries has to go to the root partition too sounds like it could be tricky to keep it lean.

Out of curiosity, what are the advantages to separating personal data into its own partition?  It seems quite annoying being forced to make a choice in the allocation of storage for root versus non-root.

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #83 on: June 02, 2017, 02:10:52 pm »
Main reason is slight ease to keep data when replacing the system. With SSDs, we don't have to put the system or the most interesting files on the fastest disk area anymore, because everything is fast.

Indeed, I have reinstalled Arch several times in the first week because I trashed the system. But the reason remains weak. Maybe I should have put everything on one partition for simplicity.



Games that I invented 5-10 years go

I have a scrap heap of tabletop game ideas, sometimes entire games with full rule text files. Here are some of these games that weren't entirely terrible.

A two-player strategic game with secret information. You have a map with territories. New military units spawn regularly in your home territory. There is only one type of unit, like in Risk. Units take several turns to move between adjacient territories. You announce that your units move from a territory, but don't announce where they move; instead you place them on a face-down card that names the target territory. A die goes on the card along with the units, this die counts time. You can time your attacks such that units from different territories arrive at a target territory at the same time. The game is feels very slow and bureaucratic.

A solitaire with 52 face-up cards dealt to 10 tableau piles spread downwards. You can move single cards to build downwards regardless of suit (e.g., place a frontmost 8 on a frontmost 9). You can also build upwards in suit. Upwards builds (e.g. 5-6-7-8 in spades, with the 5 buried deepest) can be moved as a unit (the example 5-6-7-8 in spades can be be built on the 4 of spades, or on a 6 of any suit). Free spaces can accept any single card or upwards built. You win if you assemble all four suits in four long upwards builds.

Cluedo (a.k.a. Clue) without a board or dice, only with the cards. It's perfectly possible to play with three suits of varying length from a standard deck. Every turn, you suspect a triplet or make an accusation. It feels like this must be a very smart game, but I'm sure there are better deduction games.

A multiplayer trick-taking card game with more than 4 suits, but it works in a pinch with 4 suits. Card ranks are ordered, like in most trick-taking games, but suits are ordered too. In the 1st, 3rd, 5th, ... trick, you must follow suit. If you can't follow suit, you may trump with the lowest-ordered suit. In the 2nd, 4th, 6th, ..., trick, you must follow rank. If you don't have a card of the given rank, you may trump with the lowest-ordered rank. With 3 or more players, this game is really chaotic and we didn't see much strategy in it. But it's not a good beer-and-pretzels game either because the rules are so unintuitive.

A game where every player puts some cards from his hand face-down onto one shared pile, then everybody guesses or bets on the entire pile's content. This should be interesting because everybody knows other things about the pile. But I didn't find a good ruleset around this idea, it felt like a lottery. In hindsight, if you can somehow react to other players' guesses by adjusting your guess, we get close to Liar's Dice, a good game.

-- Simon
« Last Edit: June 02, 2017, 03:38:10 pm by Simon »

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #84 on: June 15, 2017, 11:15:37 pm »

I've never took computer science classes, therefore I never had to write this lovely toy program. I did it for fun tonight. The math isn't hard, the programming isn't hard, but the images are as awesome and intriguing as ever.

<SimonN> the standard mandelbrot belongs to f(z) = z^2 + c, this weird insect-like set is f(z) = z^2.1 + c
<mobius`> that's flippin' crazy man
<SimonN> I wouldn't want this to crawl into my bed at night >_>


Also attached is a bonus image that I generated on the next day, from the Burning Ship.

-- Simon
« Last Edit: June 17, 2017, 12:07:58 am by Simon »

Offline mobius

  • Posts: 1962
  • The Owls are not what they seem
    • View Profile
Re: Simon blogs
« Reply #85 on: June 18, 2017, 06:20:38 pm »
what is the equation for the last (new) one?
and why is it cutoff at the bottom or is this normal? Is that the limits of the program?

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #86 on: June 18, 2017, 06:28:39 pm »
Iterate f(z) = (|Re z| + i |Im z|)^2 + c.

Burning Ship fractal on Wikipedia. I plotted one of the small ships at the left side. Nice zoom anim on youtube.

My image is cut off because I zoomed in on a part. The entire fractal has a unique shape, but I like these towers even better.

-- Simon
« Last Edit: June 18, 2017, 09:50:18 pm by Simon »

Offline mobius

  • Posts: 1962
  • The Owls are not what they seem
    • View Profile
Re: Simon blogs
« Reply #87 on: June 19, 2017, 01:17:00 am »

Games that I invented 5-10 years go

I have a scrap heap of tabletop game ideas, sometimes entire games with full rule text files. Here are some of these games that weren't entirely terrible.


I'd like to see more of those if you're willing to share. The clue one sounded like a good idea I want to try that out, and maybe the others too. I used to play lots of cards years ago but haven't for a long time. Recently I've started getting back into it.

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #88 on: June 20, 2017, 04:28:36 am »
More renderings of the Burning Ship. This is the most beautiful math I've ever done. :lix-blush:

The color scheme is discontinuous. I defined an arbitrary cutoff: How many iterations are still dark blue air, and how many iterations are the fiery-orange towers or sails? I chose 20 for the first and 23 for the second image. The more iterations a point takes to escape, the lighter the sails become.

(Re more games: I plowed through my collection, but no more sprung forward as worthwhile. Maybe one-card poker? Impose a linear order on all cards, i.e, order by suit whenever rank is equal, deal a card to each player. Start player posts a blind, then you have one street of betting. Highest card wins among the non-folders.)

Bonus image for Icho:
Armada to the left of the main fractal in 6240x1560.
Armada with transparent bg
Armada, only the background in blue

-- Simon
« Last Edit: August 08, 2017, 09:15:33 pm by Simon »

Online Simon

  • Administrator
  • Posts: 1917
    • View Profile
    • Lix
Re: Simon blogs
« Reply #89 on: August 16, 2017, 06:39:12 am »
So Long Sucker

Found a strange 4-player tabletop game, So Long Sucker, invented by John Nash and others. If the linked rules on Wikipedia aren't clear -- the game appears subtle on first read -- consider the rules PDF linked on Wikipedia, and read that too. I believe I have fully understood the rules.

The driving mechanic: On your turn, you must make a play, thereby diminishing your stash of chips. You lose if it's your turn and you're out of chips. But having the move can be very good also, because you can capture chips under special conditions. You must decide whose chips to remove from the game, and you must decide who gets the next turn.

Coalitions, or agreements to cooperate, are permitted, and may take any form. No penalty for failure to live up to an agreement.

I don't dare to suggest play-by-forum. :lix-evil: In the negotiation games, you make and break your alliances as you see fit. That can leave even seasoned gamers with a sour aftertaste for weeks. To compare, the Lemmings Mafia went well, nobody got sour from Mafia -- but the teams were determined by the game. You don't backstab in standard Mafia.

-- Simon