handmade.network » Forums » switching from OOP to procedural
mmozeiko
Mārtiņš Možeiko
1670 posts
1 project
#15074 switching from OOP to procedural
1 month ago

AlexKindel
I'll have to look into metaprogramming. Maybe it would be more powerful than C#'s generic capabilities

Generics are not close to "meta-programming". But C# has very powerful "meta-programming" capabilities called T4 Text Templates: https://docs.microsoft.com/en-us/...-generation-and-t4-text-templates You can generate whatever code you want during compilation time. This allows you to inspect members of existing data structures, generate new types, code, etc...
Lokathor
3 posts
#15077 switching from OOP to procedural
1 month ago Edited by on April 25, 2018, 1:58 a.m.

What helped me the most in switching far away from Java/OOP was to go to the "polar opposite": Haskell/PureFP.

You lose the tools you're familiar with, and instead of replacing them with similar looking tools that you should use in a different way (eg: C/C++/Golang/etc), which lets you fall back on your old ways, you're given a totally new set of tools and you have no idea how they work at all. It lets you unlearn your assumptions of how to model a problem and build up a solution. I've since moved from Haskell to Rust, but I still think that Haskell is the best way to break your mind out of OOP-mode.

Rustacean / Haskeller / HH in Rust
forkingpaths
Martin Fouilleul
44 posts
1 project

Sound Engineer / Programmer

#15078 switching from OOP to procedural
1 month ago

AlexKindel
In the current project, I think it would be necessary to error check at every layer: the only kind of error that can happen beyond user syntax errors that can be caught immediately is divide by zero errors (also introduced by the user input), which often can't be detected without a lot of processing, and the moment of detection might be deeply buried, like with 1/(1+1/(2^(1/2)+3^(1/2)-(5+2*6^(1/2))^(1/2))^(1/2), where 2^(1/2)+3^(1/2)-(5+2*6^(1/2))^(1/2) happens to equal zero.


You could maintain a rational number in each node, which is the result of the operation, that you can compute while simplifying. Thus you can detect subexpressions that evaluate exactly to 0. (You can also just maintain a float and approximate the result of the operation, so you can handle irrationals, but some expressions that don't evaluate to zero might produce a zero floating point value and vice versa). Now you only have to error-check when simplifying / evaluating a division node.

Error handling itself can be viewed as a simplification rule : if an operation has one child that contains an error, replace the whole subtree with that error. You could also tag nodes with a character index indicating where the node is located in the source, so that when an error occurs, the whole tree is simplified to an error node indicating the position of the error.

Martin
hasen.judy
4 posts
I'm making a mobile application for the Ryoukai Japanese-Arabic dictionary.
#15080 switching from OOP to procedural
1 month ago

The way you designed your Nodes/Terms seems perfectly natural to me and is basically how you would model the thing in C anyway.

Each node in the expression would have a tag to specify its type and then it would have some values that are particular for its type.

> I've ended up with towering class hierarchies

Looking at what you showed us so far, I don't see any "towering class hierarchies". I just see sensible representation of data.

The one small "weirdness" is you have "Number" as a root but it's not doing anything. You don't need it. You already have a way to represent numbers with the `Integer` type.

What I would do is use Term as the basic representation every where, so for example, the fraction type would be:

1
2
3
4
5
class Fraction : Term
{
    Term Numerator;
    Term Denominator;
}



You can also have a much simpler representation: only two types of nodes:

1
2
3
4
5
6
class BinaryTerm : Term
{
    Term left;
    Term right;
    Operation op;
}


Where `Operation` could be an enum.

The other class would be a leaf for representing the actual integers:

1
2
3
4
class Number: Term
{
    int value;
}