I'm not sure why you're bringing up FP and Rust here. The idiomatic FP and Rust versions of the code in the article would be similar to the fast version: you use algebraic data types to represent your Shape type (which are just tagged unions under the hood, exactly like in the article) and pattern match on the type, which can be compiled to a jump table (exactly like in the article).
And I think neither FP nor Rust discourage the internal-representation-dependent 10x optimization. They only discourage doing this across module boundaries, but the style of programming encouraged by FP and Rust encourages putting your datatype variants together in one module (unlike OOP).
So with those languages you're much more likely to naturally arrive at a fast solution than with traditional OOP.