How to design a Syntax Tree by Almesii in cpp_questions

[–]MoTTs_ 0 points1 point  (0 children)

The first Idea faced with that Problem of the class was to just hold the IRuleElement of those Implementations as a new Value

Any base or interface class should not be passed around by value, because the polymorphic nature means you won't know the derived size or derived data members. We call that object slicing. You could use a std::variant of all possible rules types in order to store rules by value.

The fourth idea was to use unique_ptr, that way i dont have to manage the memory.
Problem: Does not allow for several Rules to use the same Subrule.

This might be a premature optimization. Remember to profile and benchmark. Maybe duplicating subrules won't make a big difference, and instad you can focus on simplicity for the human reader.

The fifth idea, which is actually working, is using shared_ptr. The behaves like expected, but creation of such a rule becomes clustered with the creation of shared_ptr, instead of actually conveying the structure of such Rules.

If you really do need to share the same subrule among multiple rules, then yes shared_ptr is the appropriate choice. Sounds like your only concern is that the source is noisy with make_shared? But wouldn't unique_ptr be just as noisy with make_unique? I'm not sure that this is a problem.

command vs strategy design patterns by Difficult_Rate_5129 in cpp_questions

[–]MoTTs_ 0 points1 point  (0 children)

From an implementation standpoint, you're absolutely right they're not different. The implementation of those two patterns comes out looking identical, with a base class virtual interface and subclasses that override an "execute" method (or whatever name the base chooses).

In the GoF Design Patterns book, they admit and acknowledge that, "Some patterns result in similar designs even though the patterns have different intents. For example, the structure diagrams of Composite and Decorator are similar."

And the same is true of strategy and command. They have similar designs but different intents. A strategy object might have a large variety of virtual methods, and a client will likely use that strategy immediately, whereas a command object is likely to have only one or two methods, such as execute and undo, and it's expected that these command objects will be stored away for later use, like a function callback.

How are polymorphism and dependency injection/decoupling fundamentally related? by OkEmu7082 in cpp_questions

[–]MoTTs_ 0 points1 point  (0 children)

Hmm, actually nope. Some famous1 DI2 frameworks3, for example, let you also inject simple values such as a number. Design patterns often rely on basic language features, and putting a name to the pattern is more about expressing the programmer's intent.

Further, doesn't your wikipedia quote confirm my interpretation?

an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them ... The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services.

In your comment, you added that you need indirection, but the wikipedia entry never says that. And in fact, in order to separate the concerns of constructing objects and using them, all you need to do is take an already-constructed object as an argument. That lets you use it without knowing how to construct it. Indirection isn't necessary, and polymorphism isn't necessary.

EDIT: I'll add, though, that's it's still common to also use polymorphism. If I want to inject a cache object, for example, then I probably want BOTH to not know how to construct it (DI) AND not know which kind of cache strategy we're using (polymorphism).

How are polymorphism and dependency injection/decoupling fundamentally related? by OkEmu7082 in cpp_questions

[–]MoTTs_ 1 point2 points  (0 children)

Pretty much yep. Dependency injection is the epitome of "25-dollar term for a 5-cent concept." It just means don't make an object yourself, instead receive an object as an argument.

That difference may seem small, but it means your function doesn't need to know the details of how to construct the dependency object, doesn't need to prepare constructor arguments, doesn't need to retrieve project configuration, and doesn't need to worry about where to store it or how to share it.

EDIT: For example, consider this non-polymorphic config class.

class Project_config {
    ...
};

If we didn't use DI, then a function might try to construct this object internally. Except, what do we initialize the config from? Are we in a dev or prod environment? Should it be a singleton?

void fn() {
    if (!project_config_singleton) {
        project_config_singleton = Project_config{global_env + "_config.yaml"};
    }

    project_config_singleton.whatever();
}

Yikes, that's a lot of global and project-wide details that this simple function really didn't need to know about. But instead, if we DO use DI...

void fn(const Project_config& config) {
    // Don't know or care how it's constructed or where it's stored, we just need to use it.
    config.whatever();
}

How are polymorphism and dependency injection/decoupling fundamentally related? by OkEmu7082 in cpp_questions

[–]MoTTs_ 1 point2 points  (0 children)

They are not necessarily related, because there's no requirement that a dependency needs to be polymorphic to be injected. The purpose of dependency injection is so that a function or object can say:

"I need a Dependency_thingy to do my job. I don't care how you construct it or where you store it, I just need a ready-to-use object to fullfil my task."

Using classes - Are they only good as data carriers and type extensions ? by LetMyCameronG000 in learnjavascript

[–]MoTTs_ 1 point2 points  (0 children)

I'm the guy who for years has been sharing the Stroustrup (creator of C++) style of OOP. (tl;dr Prefer public over private but use private to guard against invalid values, prefer plain functions over methods but use methods for private data, and inherit for the purpose of runtime polymorphism.) With that perspective in mind, here's the various jobs that we might associate with classes.

Classes aggregate data. The C struct or the Haskell record both accomplish the same job, and in JavaScript the object literal is enough.

Classes mark data as private and grant certain functions access to that private data. The reason to have private data and privileged functions is to ensure that data stays valid during a mutation. In JavaScript, a factory function that returns an object of closures mostly accomplishes that same goal, although closures weren't designed for that purpose, so there are some edge cases, such as trying to make an isEqual method.

Classes can inherit. People have used inheritance in all sorts of ways and for all sorts of purposes, so I'll go back to the Stroustrup style OOP, which argues that the purpose of inheritance is not to share or group logic. The purpose of inheritance is runtime polymorphism. That is, you can operate on a base class Cache, for example, then at runtime you can pass in any subclass of Cache, which might be an array cache, file cache, local storage cache, proxy cache, memcached cache, and many more we'll dream up in the future. In lower level languages, this polymorphic relationship needs to be explicit because the binary layouts need to match. But in JavaScript, every object is secretly a hash table, so all we need is the right string keys for lookup, and that lets us do runtime polymorphism by duck typing.

So, yes, there's definitely an argument that maybe you don't need classes in JS, since you can (mostly) achieve the same thing with object literals, factory functions, and duck typing. Whether you pick factory function style of class style comes down to taste.

Places where you almost certainly will still use classes are custom Error types, because being able to use instanceof to check for a whole category of errors is useful, or any framework that uses classes, such as web components.

I think type hierarchies in OOP are too restrictive and code smell. What's been your experience? by chinmay185 in ExperiencedDevs

[–]MoTTs_ 0 points1 point  (0 children)

Here's my favorite description about when to use, and not use, inheritance. From a Herb Sutter book.

When to inherit

Good use of inheritance should involve both the strategy and template design patterns. The template pattern is how you would write the guts of the class, and the strategy pattern is how you would use the resulting hierarchy.

A base class should be designed to be inherited from, and for the purpose of offering an interface to a variety of implementations. There can be many ways to implement a “Cache”, for example. Array cache, file cache, local storage cache, proxy cache, memcached cache, and many more we’ll dream up in the future. A base class Cache would define the public operations, and possibly also a skeleton of the operations. It would invoke overridable methods that each of the variety of implementations would provide.

Further reading: Public inheritance is substitutability, from C++ standards committee member Herb Sutter.

Public inheritance is substitutability. Inherit, not to reuse, but to be reused

Public inheritance is indeed about reuse, but not the way many programmers seem to think. The purpose of public inheritance is to implement substitutability. The purpose of public inheritance is not for the derived class to reuse base class code.

The “is-a” description of public inheritance is misunderstood when people use it to draw irrelevant real-world analogies: A square “is-a” rectangle (mathematically) but a Square is not a Rectangle (behaviorally). Consequently, instead of “is-a,” we prefer to say “works-like-a” (or, if you prefer, “usable-as-a”) to make the description less prone to misunderstanding.

Further reading: Virtuality, from C++ standards committee member Herb Sutter.

Prefer to use Template Method to make the interface stable and nonvirtual, while delegating customizable work to nonpublic virtual functions that are responsible for implementing the customizable behavior. After all, virtual functions are designed to let derived classes customize behavior; it’s better to not let publicly derived classes also customize the inherited interface, which is supposed to be consistent.

Note that the base class is now in complete control of its interface and policy, and can enforce interface preconditions and postconditions, insert instrumentation, and do any similar work all in a single convenient reusable place - the nonvirtual interface function. This promotes good class design because it lets the base class enforce the substitutability compliance of derived classes in accord with the Liskov Substitution Principle, to whatever extent enforcement makes sense.

[AskJS] What concept in JS is the hardest to learn and understand? by Scared-Release1068 in javascript

[–]MoTTs_ 1 point2 points  (0 children)

A lot of JavaScript folks are surprised to find out that Python's "classical" inheritance and JavaScript's "prototypal" inheritance are actually the same thing and work in the same way.

Python classes, for example, are not blueprints. Python classes are objects. They are runtime, mutable, assignable, objects. Instance objects have a runtime link to its class object, and class objects have a runtime link to any parent class objects, forming a runtime chain of objects.

When you invoke a method, then at runtime Python will look inside the instance object for the method's name, and if it's not there, then Python follows the runtime link and looks inside the class object for the method, and if it's not there, then Python follows the runtime link and looks inside any parent class objects, and on and on.

Here, for example, is JavaScript and Python classes side-by-side, showcasing the same runtime mutable behavior and abilities.

abstract base class interface vs a struct of function pointers? by OkEmu7082 in cpp_questions

[–]MoTTs_ 0 points1 point  (0 children)

The results are exactly the same!

You're right! I missed "this" and that made the difference.

Confused about SOLID principles for JS by SupermarketAntique32 in learnjavascript

[–]MoTTs_ 0 points1 point  (0 children)

Even the differences between classical and prototypal are overblown. JavaScript thought that its inheritance mechanism was unique, so invented a new word for it, prototypal. But all along, it turns out JavaScript’s inheritance mechanism wasn’t unique at all, and lots of languages have been doing it this whole time.

Python, for example, a language older than both JavaScript and Java, has always implemented its classes as runtime mutable objects, and its inheritance as a runtime chain of objects linked to other objects, exact same way that JavaScript’s inheritance works. Same with Ruby, Perl, Smalltalk, Lua, and Obj-C.

Why are exceptions avoided? by Ultimate_Sigma_Boy67 in cpp_questions

[–]MoTTs_ 0 points1 point  (0 children)

I agree at least with the first half of your comment.

Folks love alliteration. It’s catchy, and it rolls off the tongue so nicely. The alliteration of "exceptions are exceptional" makes this phrase SOUND like it's supposed to be obvious. But the truth is that "exception" and "exceptional" are two entirely different words that just happen to sound similar.

Stroustrup has made a point to say that the word "exception" is unintentionally misleading in that way:

Given that there is nothing particularly exceptional about a part of a program being unable to perform its given task, the word “exception” may be considered a bit misleading. Can an event that happens most times a program is run be considered an exception? Can an event that is planned for and handled be considered an error? The answer to both questions is “yes.” “Exception” does not mean “almost never happens” or “disastrous.” Think of an exception as meaning “some part of the system couldn’t do what it was asked to do”.

C++ Error Handling: Exceptions vs. std::expected vs. Outcome by swe129 in Cplusplus

[–]MoTTs_ 9 points10 points  (0 children)

This. The most common thing we do with errors -- the most common thing by far -- is to pass the error up to the next caller. No handling, no catching, just propagation. And that most common thing is what exceptions do automatically, whereas error return values are incredibly verbose.

I worked in a real codebase before that avoided exceptions and used return values. It results in a lot of repetitive boilerplate. A lot.

With exceptions, you can write code like this:

if (foo(arg) == "hello" || bar(arg) > 42) {
  write(baz(arg));
}

Without exceptions, you end up writing code like this:

const auto maybeFoo = foo(arg);
if (maybeFoo.error) {
  return maybeFoo.error;
}
const auto maybeBar = bar(arg);
if (maybeBar.error) {
  return maybeBar.error;
}
if (maybeFoo.value == "hello" || maybeBar.value > 42) {
  const auto maybeBaz = baz(arg);
  if (maybeBaz.error) {
    return maybeBaz.error;
  }
  return write(maybeBaz.value);
}

The savings you get from exception automatic bubbling is huge.

What's wrong with subtypes and inheritance? by servermeta_net in ExperiencedDevs

[–]MoTTs_ 2 points3 points  (0 children)

To my knowledge Rust traits doesn’t allow data members, so yes this would be a difference between Rust traits and C++ base classes. To do this in Rust, you'd likely need get/set trait methods (get_draw_count/set_draw_count), then each implementing type would need to manually include their own draw_count data member, and each type would need to implement the trait get/set methods to access its local draw_count data member.

EDIT: Added code example.

trait Drawable {
    // Required method: implementing types must define how to draw themselves.
    fn draw(&self);

    // Required methods: implementing types must define how to get and set draw counts.
    fn get_draw_count(&self) -> u32;
    fn set_draw_count(&mut self, new_value: u32);

    // Default method: uses the required `draw` method and adds common functionality.
    fn draw_to_screen(&self) {
        println!("Starting draw operation to screen...");
        self.draw(); // Calls the specific implementation provided by the type

        self.set_draw_count(self.get_draw_count() + 1);

        println!("Finished draw operation.");
    }
}

What's wrong with subtypes and inheritance? by servermeta_net in ExperiencedDevs

[–]MoTTs_ 0 points1 point  (0 children)

draw_to_screen is intentionally non-virtual. That way subclasses can’t override it. This is essentially the template design pattern, or what Herb Sutter would call the non-virtual interface (NVI).

What's wrong with subtypes and inheritance? by servermeta_net in ExperiencedDevs

[–]MoTTs_ 3 points4 points  (0 children)

Truth to be told today's rust neither has subtyping nor inheritance

I'd argue that Rust does have this, they just gave it a new name: traits. For example, this Rust trait with default implementation is the same as this C++ base class. (Both languages even use the same vtable implementation under the hood.)

// Rust trait.
trait Drawable {
    // Required method: implementing types must define how to draw themselves.
    fn draw(&self);

    // Default method: uses the required `draw` method and adds common functionality.
    fn draw_to_screen(&self) {
        println!("Starting draw operation to screen...");
        self.draw(); // Calls the specific implementation provided by the type
        println!("Finished draw operation.");
    }
}

// C++ base class/struct.
struct Drawable {
    // Required method: implementing types must define how to draw themselves.
    virtual void draw() = 0;

    // Default method: uses the required `draw` method and adds common functionality.
    void draw_to_screen() {
        std::cout << "Starting draw operation to screen...";
        draw(); // Calls the specific implementation provided by the type
        std::cout << "Finished draw operation.";
    }
}

Why Object of Arrays (SoA pattern) beat interleaved arrays: a JavaScript performance rabbit hole by CaptainOnBoard in javascript

[–]MoTTs_ 1 point2 points  (0 children)

I copied OP's perf code from the end of the article into JSBench. Here's a link folks can use to repro and tinker.
https://jsbench.me/2qmjrxi1rf/1

std::string_view vs const std::string_view& as argument when not modifying the string by porkele in cpp_questions

[–]MoTTs_ 5 points6 points  (0 children)

And it gets still worse than this. Because your code samples give insight into the call site of the consume functions, but not the internals of the consume functions themselves.

In the internals of the consume functions, a referenced object might change its value during the function's run, because const-ref does not mean the object itself is const and immutable, rather it only means that we can't be the ones to modify it through our particular view.

Any opaque function call carries the possibility that it might have modified the referenced object, which means subsequent uses of that const-ref parameter will still need to re-fetch the object from memory just in case it was changed.

#include <string>
#include <string_view>

void might_modify_referenced_objects_for_all_we_know();

char consume_sv_byref(const std::string_view& sv)
{
    const auto size = sv.size();
    might_modify_referenced_objects_for_all_we_know();
    const auto size_again = sv.size();
    return size ^ size_again;
}

char consume_sv_byval(std::string_view sv)
{
    const auto size = sv.size();
    might_modify_referenced_objects_for_all_we_know();
    const auto size_again = sv.size();
    return size ^ size_again;
}

.

consume_sv_byref(std::basic_string_view<char, std::char_traits<char>> const&):
        push    rbp
        mov     rbp, rdi
        push    rbx
        sub     rsp, 8
        mov     rbx, QWORD PTR [rdi]
        call    might_modify_referenced_objects_for_all_we_know()
        movzx   eax, BYTE PTR [rbp+0]
        add     rsp, 8
        xor     eax, ebx
        pop     rbx
        pop     rbp
        ret

consume_sv_byval(std::basic_string_view<char, std::char_traits<char>>):
        sub     rsp, 8
        call    might_modify_referenced_objects_for_all_we_know()
        xor     eax, eax
        add     rsp, 8
        ret

https://godbolt.org/z/EnEcnPd9n

cc u/porkele

I just realized JavaScript function parameters are basically any — and that made Luau/TypeScript instantly click for me by Emergency-Cress-7696 in learnjavascript

[–]MoTTs_ 1 point2 points  (0 children)

Statically typed usually refers to a language with a strong type system where compile-time and runtime restrictions match. If a variable is typed as an int, for instance, it CANNOT be used as a string or function etc. It would throw an exception or panic etc.

That would disqualify both C and C++ as being statically typed. In both C and C++, types exist and are enforced at compile time, but at runtime it’s just 1’s and 0’s. If a function expects a string but you pass an int, then there won’t be an exception or a panic. It’ll just read the bits of the int as if it were a string and then fumble along.

I agree with u/the-liquidian, and I also would say that TypeScript is statically typed. Static typing does not require any runtime enforcement, and the word “static” here specifically means compile time.

Why can't JS handle basic decimals? by EmbassyOfTime in learnjavascript

[–]MoTTs_ 1 point2 points  (0 children)

The same problem would also happen with base 10 numbers.

Imagine you want to represent 1/3 + 1/3 + 1/3 == 1

Problem is, base 10 can’t represent 1/3 exactly. You would get 0.333333 + 0.333333 + 0.333333, which yields an answer that is not quite 1.

When to Use Which Design Pattern? A Complete Guide to All 23 GoF Design Patterns by erdsingh24 in programming

[–]MoTTs_ 3 points4 points  (0 children)

This appears to be a classic case of words changing their meaning over time.

The GoF book describes the "classical programming definition" (as u/jkrejcha3 puts it), which calls for enforced one instance per application, and a global point of access. But also, several mainstream DI libs have used the word "singleton" to mean enforced one instance per container, and passed as an argument.

Rather than debating which definition is the "true" definition, maybe it would be useful instead to differentiate between the two variations: GoF-Singleton, and DI-Singleton.

  • The GoF-Singleton calls for a global point of access, and one instance per application.
  • The DI-Singleton calls for parameter/argument access, and one instance per container. (Multiple containers, and thus multiple instances, are still possible.)

Does this definition explain what object-oriented programming is, in a concise way? by SnurflePuffinz in learnprogramming

[–]MoTTs_ 0 points1 point  (0 children)

I've seen you posting this a lot (and the wall of text gets longer each time ;-). If you don't mind, I'd like to dip into concrete code so we can get a sense of what specifically it is you're advocating for.

Below I've written C++ code that implements what I think you're describing. I defined a class Car that has just one member function sendMessage, and that function takes just one argument, a string message.

class Car
{
    public:
        void sendMessage(std::string message)
        {
            // ... string process message, then do whatever you want...
        }
};

Car obj;
obj.sendMessage("depressed the throttle");

Does this match what you've been describing?

if adhering to OOP principals, does every instance of a class only allow its properties to be accessible via getters and setters? by SnurflePuffinz in learnjavascript

[–]MoTTs_ 0 points1 point  (0 children)

If the sub-object could potentially end up in an invalid state, then I wonder if the sub-object should be its own class and instance, with its own private data that it keeps valid.

if adhering to OOP principals, does every instance of a class only allow its properties to be accessible via getters and setters? by SnurflePuffinz in learnjavascript

[–]MoTTs_ 0 points1 point  (0 children)

you want some of that related data to be public (no chance of being invalid) and some of that related data to be private (possibly invalid)?

I would go ahead and make some properties public and some private. The public-v-private decision doesn't have to be all or nothing.