Archive for the ‘Coding’ Category

Frustration with Speed Coding Interviews

Wednesday, September 18th, 2019

Clojure.jpg

Yesterday I had an interesting phone screen with someone, and the seemingly common practice of asking a candidate to code on the phone - in a shared web-based environment again came up. I recognize that any employer can have any legal criteria for employment, and the "Coding Phonescreen" is a very common one. You get to see if the person can write code in a few minutes as opposed to inviting them for a day-long interview cycle that can cost considerably more. It's decent logic.

But it really doesn't tell the story, does it?

Speed Coding has about the same relationship to real development as a college classroom has to Jeopardy!... yeah, the material is the same, but the skills to be able to do well in one do not necessarily translate to the other. And the most critical skill in the speed forms is pattern recognition of the problem.

If you've seen this problem before, and written a simple solution to it, then you're in good shape. You know the flow, you know the pitfalls, and you can talk your way through it - like you're talking your way through directions to a local restaurant. No pressure, you're showing someone something you know, and it happens to take a few steps. No biggie.

But if you're at all unsure, then you're not going to get time to think about the solution before being expected to answer it. This is the problem with Speed Coding - if you know the answer, it's fine. But then it's not really seeing if you can think on your feet... if you don't know the answer, you're likely going to make one or two edge-case mistakes, and those will be clearly visible to the person that knows the solution.

The problem I ran into was a binary tree issue, and while I had been practicing my Speed Coding in Clojure, the nature of the binary tree really leaned towards a C++ solution, and that was not horrible, but it was a lot less friendly to edge-conditions.

I ended up writing something like this:

  struct Node { int value; Node *left; Node *right };
 
  bool stored(Node *me, op) {
    bool   retval = true;
    if (retval && (me->left != NULL) && (me->left op me->value)) {
      retval = stored(me->left, op);
    }
    if (retval && (me->right != NULL) && (me->value op me->right->value)) {
      retval = stored(me->right, op);
    }
    return retval;
  }

and the missed edge-case is that once you are one, or more, steps down in the tree, it's possible to have the relative position of the values be correct, but the absolute position to be false. There are two ways to solve this, in this code:

  1. Pass limits down with the call - this could be done with max and min arguments and then in the recursive calls, place the correct values there, and test them as well.
  2. Scan up the tree on each check - this could be a walk-up the tree and check to see that you aren't in violation of the location you have. This would take more time because of all the walking, but it'd work.

But what I'd wanted to do was to write it in Clojure, but the data structure didn't jump out at me. Until this morning. 🙂 This morning I spent the minute or two thinking about the data structure, and then formulated the following solution:

  ;; [val left right]
  ;;       10
  ;;    5      15
  ;;  1   7  12   20
  (def good [10 [5 [1] [7]] [15 [12] [20]]])
 
  ;;       10
  ;;    5      15
  ;;  1   17  12   20    -- the 17 is out of place
  (def bad [10 [5 [1] [17]] [15 [12] [20]]])
 
  (defn sorted?
    "Function to check a binary tree to see if it's sorted for proper
     searching."
    [[v lt rt] op]
    (let [ltv (first lt)
          rtv (first rt)]
      (and (or (nil? lt) (and (every? identity (map #(op % v) (flatten lt)))
                              (check lt op)))
           (or (nil? rt) (and (every? identity (map #(op v %) (flatten rt)))
                              (check rt op))))))

What I really like about this solution is that it checks the entire subtree with the operation. This means that the effort to do one, is really checking all of them. This is what I wanted to write, and it works perfectly.

But I didn't force the issue, and pull back and take the time to think. My mistake. I won't make it again.

UPDATE: a friend and I were talking about this same problem, and he came up with a solution that was very clever - the structure can be validated by simply assuming that the structure is a sorted binary tree, and then calculating the min and max values of the tree.

The catch being that if you get to a node where the current value isn't within the min and max, then you have to fail, and return nil. It's really quite amazingly simple in that it's very fast, very easy to understand and adds the additional benefit of returning the extremum of the tree.

  (defn bst-rx*
    "returns extent [min max] of valid bst or nil if invalid"
    [t]
    (cond
      (nil? t) nil
      (vector? t) (let [[v l r] t
                        lx (if l (bst-rx* l) [v v])
                        rx (if r (bst-rx* r) [v v])]
                    (when (and lx rx (<= (lx 1) v (rx 0)))
                      [(lx 0) (rx 1)]))
      :else [t t]))
 
  (defn bst-rx?
    [t]
    (boolean (bst-rx* t)))

Thrown for a Bit of a Loop

Tuesday, September 17th, 2019

hostmonster.jpg

Yesterday morning, I thought to check my blog and see something, but to my complete surprise, it was down. Like very down, and I had no idea what was happening. I've been using WordPress and HostMonster for more than a decade, and I've never had anything even remotely like this. I didn't know where to start - so I went to their admin site, thinking I'd been hacked somehow...

First, it was clear that they had done a ton of upgrades to the host and its support platform. Massive changes. So the first thing was to get logged in. This was a little odd because it wasn't working on Safari, and it had been in the past - so I switched to Chrome, and finally got logged in. Step 1 - accomplished!

Then I looked at the installed users on each of the three WordPress sites I have, and in each case, there was a user that I couldn't explain. It certainly appeared to me that these were bad actors, and I had no idea how they got there. I stay up to date, don't allow logins, don't allow replies... it's a Journal more than anything else. But still... I could not deny these accounts. So I asked for help.

php.jpg

It took a long while to figure this out, but in the end, the logs for the site indicated that there was a PHP problem in one of my plugins, and one of my themes. Why this happened yesterday wasn't at all clear, but it became clear as I dug further.

HostMonster had dropped support for PHP 5.x, and the only versions available to me were 7.0, 7.1, 7.2, and 7.3, with the latter being the default. Now it seemed to be clear what had happened... nothing had changed, but in all the upgrades for the infrastructure on the hosts, they had switched to a different config for PHP, and the plugin and theme were doing something that they shouldn't. OK... now to the code.

The first one I tackled was the plugin, as the error in the logs was pretty clear. I did a quick search for =& and sure enough, it was a PHP 5-ism, and that was easy to fix. That solved the plugin problem, and it loaded and ran fine. The theme had a different problem with a deprecated function that wasn't really even needed in the theme, but I found a replacement, and used that, and the theme was fine.

All told, this took more than 5 hours... it was not quick, and I just ahead of the part where I found out that the timezone plugin I was using wasn't needed in WordPress 5, and so I didn't put that back into play, Also, when I got the site up, it was possible to see the errors on activation of the plugin (but not the theme), which made continued debugging a lot easier.

In the end, it was all cleaned up, and now it's set for PHP 7. I'm glad that there wasn't a bigger issue, but I really have to be careful of these things because there is almost no support for the plugin and theme - and I really like to have both of them working for me for this blog. 🙂

Very Funny Tweet about Scaling

Tuesday, July 9th, 2019

Amazon EC2 Hosting

Yesterday I saw this very enjoyable tweet and it made me smile - quite a lot... because I do interviews often, and they are almost always about Architecture and Design, and scaling is one of the key use-cases to explore. It really helps see how the candidate approaches the problem:

Used to pay $5/mo on a small instance for my personal site. Then I discovered Kubernetes and realized my site didn't scale! No canary deployments! So I upgraded and pay $200/mo now. Took weeks to configure. Millions of people can now read my resume. Damn, it's never looked better
-- @malaroto

When faced with a scaling problem, AWS has been amazingly good - and amazingly bad for junior developers on the path of learning their craft. On the up-side, it's wonderfully full-featured, stable, available, on-demand in every way, and global. On the downside, it doesn't require any effort to use - so the first answer most jump to, is to build something that doesn't need to be built with unnecessary complexity that will work, but slows down the ability for someone else to understand the solution, and it's basically just wasting money.

"Not my dime" - is accurate, but not really the point. The point is to understand the problem, and then fix the problem, but if everything is able to be solved with millions of dollars of computing infrastructure, there seems to be no motivation to solve it with an hour of understanding and code refactoring.

So I giggle... they will have their day - a massive supercomputer in a grain of sand - ubiquitous and omnipresent... and then there will be no need to understand the why of issues... and that will be too bad. There will always be a need for craftsmanship.

RedHat Assumes Stewardship of OpenJDK 8 and 11

Monday, April 22nd, 2019

java-logo-thumb.png

Interesting, that a few days after I move off Oracle's JDKs for my laptop, RedHat announces that it's going to assume stewardship of OpenJDK 8 and 11 from Oracle. It seems that Oracle wants to get out of the enterprise java business as it moved J2EE support to the Eclipse Foundation, and this just makes it clear that they really don't want to be in the Java business - at all.

This could be that they can't make enough money on it - or that they are just more interested in GraalVM, which they control, and can be used to compile a large subset of Java code into machine code. With this control, what do they need with the OpenJDK spec? It's just weight and cost. Better to get someone else to take care of that, and get back to making money licensing what they can.

It's just sad, but all too familiar, with Oracle. Glad I moved off. I'll stick with AdoptOpenJDK until there's a reason to move.

Finally Updating to AdoptOpenJDK for JDK 8 and JDK 11

Thursday, April 18th, 2019

java-logo-thumb.png

This morning I decided to really dig into the Homebrew support for AdoptOpenJDK - and while I was initially a little unsure of the AdoptOpenJDK group, after reading their web site, and digging into their Homebrew cask, I was convinced to give it a try. It will keep things moving with updates on the JDKs - delivering JDK 1.8.0r212 as of today, and that's what my biggest fear was. So let's get to it.

In order to get the very latest AdoptOpenJDK (11), it was as simple as:

  $ brew cask install adoptopenjdk

which resulted in my installation directory looking like:

  $ ls /Library/Java/JavaVirtualMachines/
  1.6.0_26-b03-383.jdk/    jdk1.7.0_45.jdk/         jdk1.8.0_144.jdk/
  adoptopenjdk-11.0.2.jdk/ jdk1.7.0_51.jdk/         jdk1.8.0_181.jdk/
  jdk-10.0.2.jdk/          jdk1.7.0_75.jdk/         jdk1.8.0_40.jdk/
  jdk1.7.0_13.jdk/         jdk1.8.0_131.jdk/        openjdk-11.0.2.jdk/

At this point, I could remove the openjdk-11.0.2.jdk/ install, as that's from Oracle, proper, and I really just want to let that go due to the licensing...

  $ brew cask uninstall java

and then re-select the correct JDK 11 with:

  $ setjdk 11; echo $JAVA_HOME
  /Library/Java/JavaVirtualMachines/adoptopenjdk-11.0.2.jdk/Contents/Home

So it was installed properly, and picked up the new installation from AdoptOpenJDK. Good. Now in order to pick up the older versions, we can follow the instructions on the Homebrew cask:

  $ brew tap AdoptOpenJDK/openjdk
  $ brew cask install adoptopenjdk8

and after this, we have the following installed on my machine:

  $ ls
  1.6.0_26-b03-383.jdk/    jdk1.7.0_13.jdk/         jdk1.8.0_131.jdk/
  adoptopenjdk-11.0.2.jdk/ jdk1.7.0_45.jdk/         jdk1.8.0_144.jdk/
  adoptopenjdk-8.jdk/      jdk1.7.0_51.jdk/         jdk1.8.0_181.jdk/
  jdk-10.0.2.jdk/          jdk1.7.0_75.jdk/         jdk1.8.0_40.jdk/

and I have to admit, I'm a little concerned about the lack of a release number on the AdoptOpenJDK 8's directory - but maybe that will be handled a little differently as they version them. We will have to wait and see.

At this point, we can:

  $ setjdk 1.8; echo $JAVA_HOME
  /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
  $ java -version
  openjdk version "1.8.0_212"
  OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_212-b03)
  OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.212-b03, mixed mode)

To make sure that we don't cleanup the old versions with Homebrew, when I install a new one, I added the following to my ~/.bashrc:

  export HOMEBREW_NO_INSTALL_CLEANUP=1

Which Homebrew says will keep from doing the automatic cleanups on the installs.

To do a final check with the AdoptOpenJDK 1.8.0r212, I checked what Leiningen was saying:

  $ lein --version
  Leiningen 2.8.3 on Java 1.8.0_212 OpenJDK 64-Bit Server VM

At this point, I've got AdoptOpenJDK 1.8.0r212, and 11.0.2, and updating each is very simple with brew. I just need to:

  $ brew update
  $ brew cask upgrade adoptopenjdk
  $ brew cask upgrade adoptopenjdk8

and then when I want, I can clean up the older versions with:

  $ brew update
  $ brew cleanup adoptopenjdk
  $ brew cleanup adoptopenjdk8

This is so much cleaner, and I don't have to worry about the crazy licensing from Oracle. It's a lot nicer place to be.

Oracle Java JDK 8r211 Updates License

Wednesday, April 17th, 2019

java-logo-thumb.png

This morning I got an update notice on Java 8 on my machine - it was for JDK 8r211, and during the normal update process, the installer popped up a dialog box where it was very clear that the terms of the license for JDK 8r211 have changed.

Specifically, it stated that this JDK was only for non-commercial use, and if it was going to be used in a commercial environment, then a license would have to be obtained from Oracle.

This is the JDK 11 license, and why I went through the pain to get OpenJDK 11 on my laptop, because I just can't see even pretending to use a product that I know I won't ever use in production. Now, I have to stick with the version of JDK 8 I've got installed, because I don't see an easy path to get OpenJDK 8 from Homebrew. There's an old cask, but I don't know that it's any more current than what I have - and I don't know that I need anything more current.

Just seems so short-sighted by Oracle, but they see a revenue stream, and go after it.

DataGraph 4.3 for Amazing Scientific Plotting

Tuesday, April 16th, 2019

DataGraph1.5.jpg

This afternoon, after reading a Master's Thesis on the prediction of the Corn Spot Prices, I was talking to a friend about using Mathematica, and how much I'd really enjoy getting back into the mathematically-based work I did in my Thesis, and how if this new work was put in a service, Clojure would be the obvious choice, and plotting would be easily done with DataGraph, which is just a beautiful way to create publication-quality plots.

Here's an evolution of an electron pulse evolution in GaAs:

GaAs Pulse Evolution

I've been using this for years, and now I read in the 4.4 beta release notes, they are going to be adding tools to make it easier to get data into the app, and so it might make it all a lot easier for me and intergrating it with Clojure. That would be very nice.

Accessing Gists from the Desktop

Wednesday, April 10th, 2019

GitHub Source Hosting

This morning I was thinking about the snippet manager I saw on Twitter... and then I realized that Gists on GitHub are exactly that - and why not just check out the status of the Sublime Text 3 plugin that deals with Gists... and the Vim plugin to do something similar.

I had to update the access token for the Sublime Text 3 plugin, and then it was working fine. But one thing I noticed was that the Gists showed up in the editor as modified files. While that's understandable if you realize the model for this is to read the Gist, and then paste it into the editor window, it's not really the workflow I expected to see.

Additionally, the syntax highlighting wasn't being triggered, so the Gists all had the syntax type of 'Text' - which was really annoying... given that the extension was exactly what you'd need to trigger the syntax type of the file. So that wasn't as nice as I expected. But it still worked.

Then I went to Vim and updated the Gist plugin, and that was interesting, but not as horrible as it could be. Still... it's a bunch of command-line steps, but it's OK. Again, there was another auth token from GitHub, which is nice, but that's about it.

The difference is that when you load a Gist into a Vim buffer, it is not seen as modified, and the syntax highlighting is correct. So those are nice to see in Vim, and while it's not amazing, it is nice to see it done right.

In the end, I'm glad to have updated these things - even if I really wish there was a nice macOS client like Dash that worked with Gists.

Updating my WordPress CodeHighlighterPlus to GeSHi 1.0.9.0

Thursday, March 28th, 2019

wordpress.gif

This morning I decided to see if I couldn't fix the Swift highlighting on this blog by updating to the latest GeSHi 1.0.9.0 - which is now using PHP 7, and as it turns out, so is HostMonster, so I'm in luck! 🙂 At the same time, I really wanted to document all the components and links so that this post makes it a lot easier to update things later.

As a point of reference, the CodeHighlighterPlus project is based off the CodeHighlighter WordPress plugin, and it's not bad - it's just not been updated in many years, and there are a lot of added languages in that time. Still... I tip my hat to the original authors, as I couldn't have done it without them.

The steps to do this required a little digging, but that wasn't bad - in that I had a few posts about this process already, and so let's just repeat them here to make sure it's all clear for the next time. I started by making sure that my local CodeHighlighterPlus plugin was up-to-date with the GitHub repo. All good, so let's get the latest code from GeSHi, and just overlay it on the local repo. Replace where necessary, and then we're up to date with GeSHi... but it's not really cleaned up the way I like it.

The next thing was to update the geshi.php file for a few changes. The first thing I wanted to tackle with CodeHighlighterPlus was the line numbers. There was far too much space between the lines in a code sample with line numbers. This is corrected simply in the style for the lines:

  1. /**
  2.   * Line number styles
  3.   * @var string
  4.   */
  5. protected $line_style1 = 'font-weight: normal; vertical-align:top;';
  6.  
  7. /**
  8.   * Line number styles for fancy lines
  9.   * @var string
  10.   */
  11. protected $line_style2 = 'font-weight: bold; vertical-align:top;';

to:

  1. /**
  2.   * Line number styles
  3.   * @var string
  4.   */
  5. protected $line_style1 = 'margin: 0; font-weight: normal; vertical-align:top;';
  6.  
  7. /**
  8.   * Line number styles for fancy lines
  9.   * @var string
  10.   */
  11. protected $line_style2 = 'margin: 0; font-weight: bold; vertical-align:top;';

The last change is for the blank lines that start, and end, the code section when you use line numbers. It's just plain annoying. Change:

  1. // Get code into lines
  2. /** NOTE: memorypeak #2 */
  3. $code = explode("\n", $parsed_code);
  4. $parsed_code = $this->header();

to:

  1. // Get code into lines
  2. /** NOTE: memorypeak #2 */
  3. $code = explode("\n", $parsed_code);
  4. // remove a blank first and last line
  5. if ('' == trim($code[count($code) - 1])) {
  6. unset($code[count($code) - 1]);
  7. $code = array_values($code);
  8. }
  9. if ('' == trim($code[0])) {
  10. unset($code[0]);
  11. $code = array_values($code);
  12. }
  13. $parsed_code = $this->header();

and we are good to go with the changes to the code. Check everything in, push it up to GitHub and we're ready to deploy it.

At this point, I just need to deploy this to each of the WordPress sites on my server - and that's as simple as:

  $ cd public_html/blog/wp-content/plugins/CodeHighlighterPlus
  $ git pull

where blog is the directory in the WordPress content for the specific blog I'm working with. I simply use GitHub as the mechanism of deployment - with a pull system to make sure it doesn't mess too much stuff up.

In this release of GeSHi, we now have support for the following languages:

4cs            e              magiksf        qml
6502acme       ecmascript     make           racket
6502kickass    eiffel         mapbasic       rails
6502tasm       email          mathematica    rbs
68000devpac    epc            matlab         rebol
abap           erlang         mercury        reg
actionscript   euphoria       metapost       rexx
actionscript3  ezt            mirc           robots
ada            f1             mk-61          rpmspec
aimms          falcon         mmix           rsplus
algol68        fo             modula2        ruby
apache         fortran        modula3        rust
applescript    freebasic      mpasm          sas
apt_sources    freeswitch     mxml           sass
arm            fsharp         mysql          scala
asm            gambas         nagios         scheme
asp            gdb            netrexx        scilab
asymptote      genero         newlisp        scl
autoconf       genie          nginx          sdlbasic
autohotkey     gettext        nimrod         smalltalk
autoit         glsl           nsis           smarty
avisynth       gml            oberon2        spark
awk            gnuplot        objc           sparql
bascomavr      go             objeck         sql
bash           groovy         ocaml-brief    standardml
basic4gl       gwbasic        ocaml          stonescript
batch          haskell        octave         swift
bf             haxe           oobas          systemverilog
biblatex       hicest         oorexx         tcl
bibtex         hq9plus        oracle11       tclegg
blitzbasic     html4strict    oracle8        teraterm
bnf            html5          oxygene        texgraph
boo            icon           oz             text
c              idl            parasail       thinbasic
c_loadrunner   ini            parigp         tsql
c_mac          inno           pascal         twig
c_winapi       intercal       pcre           typoscript
caddcl         io             per            unicon
cadlisp        ispfpanel      perl           upc
ceylon         j              perl6          urbi
cfdg           java           pf             uscript
cfm            java5          phix           vala
chaiscript     javascript     php-brief      vb
chapel         jcl            php            vbnet
cil            jquery         pic16          vbscript
clojure        julia          pike           vedit
cmake          julia.bak      pixelbender    verilog
cobol          kixtart        pli            vhdl
coffeescript   klonec         plsql          vim
cpp-qt         klonecpp       postgresql     visualfoxpro
cpp-winapi     kotlin         postscript     visualprolog
cpp            latex          povray         whitespace
csharp         lb             powerbuilder   whois
css            ldif           powershell     winbatch
cuesheet       lisp           proftpd        xbasic
d              llvm           progress       xml
dart           locobasic      prolog         xojo
dcl            logtalk        properties     xorg_conf
dcpu16         lolcode        providex       xpp
dcs            lotusformulas  purebasic      xyscript
delphi         lotusscript    pycon          yaml
diff           lscript        pys60          z80
div            lsl2           python         zxbasic
dos            lua            q
dot            m68k           qbasic

And with the addition of Swift, I have highlighting on all the code snippets I've been adding. Very nice!

On Object Oriented Designs and Complexity

Tuesday, March 26th, 2019

Code Monkeys

Today, with the update of Xcode 10.2, and Swift 5.0, I had to struggle with the formatting of strings in order to find the pattern they represented. The point is really this: Represent the pattern of the characters in a word so that 'bee' and 'too' and 'see' all look like the same pattern.. This is used in my CryptoQuip solver, and the point is to group words by their patterns because we don't know what the actual characters are, but we do know their patterns - because it's a simple substitution cypher.

So how to do that? Well... when we look at Clojure - which just deals with the string as a sequence of characters - just data, we have:

(defn pattern
  "Function to take a word (as a string) and return a vector that is the
  pattern of that word where the values are the index of the character.
 
    => (pattern \"see\")
      (0 1 1)
    => (pattern \"rabbit\")
      (0 1 2 2 4 5)
  "
  [word]
  (map #(.indexOf word (int %)) word))

and if, for the sake of this post, we drop the comments, we get something very simple:

(defn pattern
  [word]
  (map #(.indexOf word (int %)) word))

if we look at this in Swift, we see:

  extension String {
    /**
     Attributes of a string that return a string that is the pattern of that
     word where the values are the index of the character. This is a simple
     baseline pattern generator for the words so they are comparable.
 
    ```
        => "see".pattern
        "abb"
        => "rabbit".pattern
        "abccef"
    ```
     */
    var pattern: String {
      get {
        let ascii: [Character] = ["a","b","c","d","e","f","g","h","i","j","k",
                                  "l","m","n","o","p","q","r","s","t","u","v",
                                  "w","x","y","z"]
        var ans = ""
        let src = Array(self.utf8)
        for c in src {
          ans.append(ascii[src.firstIndex(of: c)!])
        }
        return ans
      }
    }
  }

And the reason to use a String as opposed to a sequence of numbers in Swift, is that those comparisons are not nearly as nice in Swift as simple String comparisons are. But I look at all this, and while the protocols in Swift are nice - to add methods to existing classes - it's much the same in Ruby, and it can lead to some very tough bugs - and so you have to be very careful using them.

And this got me to thinking about the complexity of most systems and the OOA&D systems I've seen in C++, Java, Ruby, ObjC, Swift - and it really is hard to come up with a really great design if you don't put in a ton of effort on the work. Sure... Boost for C++, and Java classes, are good designs - but they had a lot of backing and time to get right. ObjC - specifically Foundation, is well-done, but again, that was a serious investment by NeXT. But most of the non-OS-level projects... like those in the wild, they are a mess.

I don't think this is an accident. I think good, solid, OOA&D is hard because there are so many times when a method isn't clearly belonging to one object, or another - and the language might not be set up to have stand-alone functions as an alternative - Java, Scala. So they have to go somewhere, and that means that things get tossed into the closest reasonable object - as long as it's "close enough". But then 6 months later, it's a disaster. No one remembers why each method is on these objects... and the circular references require interfaces, and then implementations of those interfaces... and it just gets to be a mess.

What I believe is that the simpler the code, the better. This means more abstract. More critical thinking, and less "let's just hammer this out" work. I'm sure there are folks that can do a good job on an OOA&D project - and it could be massive and complex... but those people are rare - very rare. And in general, you end up with really bad objects that create horrible inclusion requirements, and even worse threading issues - because it all mutable, and you just have systems that can't get larger than a certain size.

That's not good. Math doesn't work that way. Neither should coding.