Author Topic: Kieran's Programming Beginner Questions  (Read 7951 times)

0 Members and 1 Guest are viewing this topic.

Offline kieranmillar

  • Posts: 286
    • View Profile
Kieran's Programming Beginner Questions
« on: November 15, 2017, 08:54:21 PM »
With the development of Lem3edit as a learning experience for me into serious programming, I predict lots and lots of embarrassing questions about C++ or git. So I thought I'd make a thread for them in the hope that the Lemmings community's resident programmers can offer some help.

My first question is about general structuring of code and classes.

Lem3edit has an editor class. This class contains everything to do with the actual level editor part of the program (imagine one day there will be other parts of the program like a main menu etc.).

The editor class creates instances of other classes and stores them in member variables. So for example, there's a Style class that stores all of the graphics for that style (Classic, Egypt or Shadow), and a Level class that stores all of the terrain pieces and objects that make up the level itself.

I'm looking to add a proper interface for adding objects and terrain to the level, and so want to split the interface in two, the "canvas" which is the main part of the screen, displaying the terrain and objects in the level and where you move them etc., and a "bar" at the bottom of the screen which contains a scrollable list of all of the terrain pieces etc. A lot like lgl2. It makes sense to me to make these separate classes, and have the editor create instances of them.

This means I now have an Editor class that has the following "Inner" classes:
  • Style
  • Level
  • Canvas
  • Bar

My problem is what to do when one of these inner classes needs to access another inner class? Clearly Canvas and Bar are both going to need access to the terrain piece graphics stored in Style, as an example. What's the best way to handle this?

My first thought is to always pass a pointer to the Editor instance when creating these member class instances. That way I can just point back to the Editor and then dive down from there. Is that the correct thing to do. Referring back to the top of the nest feels wrong to me, but maybe I'm just confusing this with the concept of inheritance?

I hope this all made sense.

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #1 on: November 15, 2017, 10:27:02 PM »
OK so I think I've gotten to the bottom of this. Ultimately I suppose there is little wrong with referencing another "module" of an object by pointing back to the top module and then diving down, so the structure of my program is probably fine.

The exceptionally stupid idea here was, instead of passing a pointer to the top module when creating the nested object and then storing it locally, I would just pass it around in the module's functions again and again so I could access it. Obviously this is really stupid and is why I was starting to have tons of pointers in all my function parameters.

I need more sleep right now, I think.

Online Simon

  • Administrator
  • Posts: 3878
    • View Profile
    • Lix
Re: Kieran's Programming Beginner Questions
« Reply #2 on: November 15, 2017, 11:51:55 PM »
Dependency injection sounds reasonable, but passing the entire Editor* looks like too much. Consider to pass only what the using class needs. E.g., the bar needs access to the style, but not to the terrain pieces already within the level.

Whether to pass the dependency anew in each call, or whether to store the pointer permanently, has no catch-all answer.

-- Simon

Offline Colorful Arty

  • Posts: 814
  • You are so loved!
    • View Profile
    • Colorful Arty's Youtube Page
Re: Kieran's Programming Beginner Questions
« Reply #3 on: November 16, 2017, 12:04:15 AM »
Indeed, make sure to weigh all of the possible implementations, and to choose the one that will be efficient either in speed or space, whichever is more prudent.
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

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

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #4 on: November 16, 2017, 09:59:15 PM »
Thanks guys. It's all starting to make more sense and I'm slowly getting somewhere.

Slowly working my way through all this pointer and constructor stuff. I understand pointers, but taking a while to get used to the specifics of C++'s language here. But I see the light at the end of the tunnel, just gotta keeping plowing through until it's second nature.

Offline nin10doadict

  • Posts: 330
  • Guy who constantly misses the obvious
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #5 on: November 16, 2017, 11:46:29 PM »
I remember using C++ in my computer science classes in college. I hated it and my code was terrible; I basically brute-forced everything. :8(): Coding just isn't my thing. Hopefully you'll have more success with it than I have.

Offline Colorful Arty

  • Posts: 814
  • You are so loved!
    • View Profile
    • Colorful Arty's Youtube Page
Re: Kieran's Programming Beginner Questions
« Reply #6 on: November 17, 2017, 12:14:27 AM »
Well, I find C/C++ particularly annoying languages to work with due to all of the low-level things you need to include in your code like memory management and pointers. And of course, the two words every computer scientist dreads most of all...

Segmentation Fault
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

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

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #7 on: November 17, 2017, 12:53:31 AM »
Today I had an awful lot of trouble with circular declarations, largely because of the nonsense errors that Visual Studio threw out meant it took me a while to understand what was even going wrong. I think I now know how to fix it, but it's late so will have to wait for next time.

I look forward to the chaos from my decision to try to slghtly restructure things ending, and I can get back to implementing cool stuff and things.

Online Simon

  • Administrator
  • Posts: 3878
    • View Profile
    • Lix
Re: Kieran's Programming Beginner Questions
« Reply #8 on: November 17, 2017, 04:21:50 PM »
Nested classes

Nested class is a class declared inside another class:

class Editor {
    int x;
    class Nested {
        int y;
    };
};


Nested classes are not inheritance. Inheritance would be wrong in the OP's design, an Editor cannot be used where a Style is required, nor can a Style be used where an editor is required.

C++ nested classes are like static inner classes in D or Java. C++ nested classes cannot access any outside object of the enveloping class. You can have an Editor::Nested and no Editor, that will work perfectly fine, it has one field Editor::Nested::y. There is no pointer to any Editor within the Editor::Nested, and there is no Editor::Nested::x because that's a field of Editor, an unrelated class.

The point of nesting is naming and possibly implementation hiding. Within Editor, the Nested is called Nested, whereas outside of the Editor, the class is called Editor::Nested. You can declare class Nested private with the usual effects: The symbol is not visible outside of Editor.

I would not use nested classes because most of the application is an editor, therefore Editor::Nested doesn't gain much over naming it Nested. But the design is not wrong either.

Everything else

The design issue from OP arises in any object-oriented language, not merely in C++.

Yes, your code in C++ gets longer than in most other languages. You can hide the allocation in wrapper structs or the standard library's unique/shared/weak pointers. But you choose C++ in the first place only when you want the low level, and have ruled out D/Rust/Crystal/... for whatever reason. Learning some C++ can't hurt either, the language is really common.

Quote
I basically brute-forced everything.

The type system is your best friend, do not betray it. :lix-scared: But yes, it requires some proficiency to become useful in the first place.

-- Simon

Offline Colorful Arty

  • Posts: 814
  • You are so loved!
    • View Profile
    • Colorful Arty's Youtube Page
Re: Kieran's Programming Beginner Questions
« Reply #9 on: November 17, 2017, 06:38:02 PM »
This is why I like Python, because it is typeless you are given much more freedom and power in your code.
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

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

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

Offline geoo

  • Administrator
  • Posts: 1475
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #10 on: November 17, 2017, 08:14:06 PM »
Well, in python you don't have to declare your types, but that makes your Type Errors appear at run time instead of compile time. So this kind of error is harder to debug in Python than in C++, they might slip under the radar more easily.
That said, I do like Python a lot as you can do many things very easily and compactly, and comparatively C++ feels like a pain. Though I think the lack of type-safety is one of the reasons python is not that popular for big projects that have to run reliably.

In C++, since C++11 you also have the auto statement if you're too lazy to infer the type yourself. I'm not sure that's considered good style though.

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #11 on: November 17, 2017, 11:14:18 PM »
Thanks guys for all the interesting comments. I picked C++ or this project for the simple reason that Mindless also wrote it in C++! But, I think C++ is useful to know. Having to be so careful and specific is helping me learn a lot, even if it can be slow going sometimes.

Simon, I looked into Nested classes but agree it does not feel like the way to go here. Each class is defined separately.

A good idea about using a struct to hold my pointers to the other objects, that makes a lot of sense.

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #12 on: January 17, 2018, 08:43:51 PM »
A question for slightly more experienced C++ers.

There are 3 things left in my lem3edit project that require some external library, ideally all of which will be cross platform, a standard file browser dialog for opening and saving files, a way to execute another program (in this case DosBox), and moving and renaming files.

I like that so far lem3edit is quite simple and involves only a small number of small libraries to set everything up. All of the above I believe can be achieved by adding something like QT or wxwidgets to the project, but I'm sort of trying to avoid using these as they look like quite large libraries. Maybe that's a mistake and I should just use them?

What do people think? Any advice from seasoned hobby program makers?

For file dialogs Tiny File Dialogs (https://sourceforge.net/projects/tinyfiledialogs/ ) looks decent. But what for the other two? I believe C++ now incorporates the file manipulation features from C++ Boost library so nothing needed there possibly. As for executing another program, C++ has the System command, but everywhere online seems to recommend avoiding that, say it's a potential security hole and resource intensive, but fails to ever explain how something like Boost.Process is any better in this regard. Maybe using System is fine given lem3edit is just a simply hobby program, but I'd like to abide by best practice if possible. Seems a shame to add the whole Boost system just for this one function though.

Online Simon

  • Administrator
  • Posts: 3878
    • View Profile
    • Lix
Re: Kieran's Programming Beginner Questions
« Reply #13 on: January 22, 2018, 04:47:33 PM »
For GUI, pick one that you like and use it. It's okay to ask other developers to install it. The larger, more well-known toolkits should be readily packaged by Linux distributions; on Windows, I can't tell what's easiest to use.

Moving and renaming files, if the GUI toolkit doesn't offer that, you can probably use Boost... though I don't know whether you can rely on only a part of Boost, or whether you have to rely on the entire package. I haven't ever used it. But very popular.

Executing another program, again, I haven't done it in a serious project. Rely on the wisdom of the internet. I'd be interested in why Boost.Process is better.

-- Simon

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #14 on: January 25, 2018, 02:47:49 PM »
Thanks for the response Simon, I think I'll go with tiny file dialogs and Boost and see how it goes. I'm not sure how much of Boost you need to install, at a glance it looks like it's modular to some extent (outside of some base and core modules).

Offline kieranmillar

  • Posts: 286
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #15 on: February 14, 2018, 08:27:47 PM »
I'm trying to improve my coding style as I go along, and want to know people's opinions about getters and setters.

Data should be private. Helps with encapsulation. Makes a lot of sense.

But if you have a class or struct that only exists to group together some related data, say as some sort of class within a class, are a bunch of trival getters and setters all that useful?

After thinking about it, I can see the argument that using getters and setters is always a good idea, because it can help with future debugging or expanding functionality of the class, if every variable access or change must be done through a function, you have an easy way to add logging or change the way it happens later, rather than digging through code for everywhere where those values were altered directly.

But I also read people on the internet moan about having a bunch of trivial getters and setters, and that objects should be designed around having an API of what actions you want to perform that result in the data being changed, rather than ever just changing the values directly. This makes a lot of sense too.

But sometimes I just want a simple class or struct that just stores some related data, so I guess in this case direct access probably makes the most sense and getters and setters should be avoided? Does it matter? Reduces overhead maybe, I don't know.

I know programmers love nothing more than a good moan, so if you have any opinions, feel free to have a whine and help me learn!

Offline Colorful Arty

  • Posts: 814
  • You are so loved!
    • View Profile
    • Colorful Arty's Youtube Page
Re: Kieran's Programming Beginner Questions
« Reply #16 on: February 14, 2018, 08:49:46 PM »
Personally I find the whole make variables private but provide getters and setters to be rather stupid. If you're going to modify variables outside the class, why bother making them private?
My Youtube channel where I let's play games with family-friendly commentary:
https://www.youtube.com/channel/UCiRPZ5j87ft_clSRLFCESQA

My Twitch channel: https://www.twitch.tv/colorfularty

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

My levelpack: ArtLems
For New formats NeoLemmix: https://www.lemmingsforums.net/index.php?topic=4583.0

Online Simon

  • Administrator
  • Posts: 3878
    • View Profile
    • Lix
Re: Kieran's Programming Beginner Questions
« Reply #17 on: February 14, 2018, 09:12:35 PM »
The idea of OO is to encapsulate behavior and data.

Merely grouping data is handy, but it's distinct from an object in the sense of OO. It's Plain Old Data, and often appears in the belly of more complex classes, or as messages that you must send manually on a very low level between two OO-style objects, e.g., over a network connection.

If every possible state of your POD is legal, and modifications to single fields of the POD don't require checks to maintain some invariant, then go ahead and make all fields public. There are many other ways to keep this maintainable, e.g., you can restrict the use of this POD to a single part of your program.

When your objects have meaningful behavior, then exposing many getters and setters is a design smell. Your class should expose a meaningful high-level protocol. The principle in OO is Tell, Don't Ask: If class A must ask class B for some data to perform some logic, consider to move this logic into class B, and merely have class A tell class B to perform the logic.

-- Simon
« Last Edit: February 14, 2018, 09:23:17 PM by Simon »

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: Kieran's Programming Beginner Questions
« Reply #18 on: February 15, 2018, 02:04:05 AM »
There are definitely some cases where you are really dealing with POD (ie. Plain old data) and therefore should just do all public fields.  For example something like a Point that captures a pair of x and y coordinates.  But even examples that seem obviously POD (or started off as such) might end up evolving into something that's no longer POD.  For example maybe you want to represent a mutable (questionable design choice, but for sake of argument we'll allow it) complex number, which can be represented in Cartesian (ie. real and imaginary components) and polar forms (ie. magnitude and phase), and maybe you want to support the ability (also questionable design, but let's just say so for sake of example) for user to change any of the four properties and have the program automatically recompute the other properties based on the change.  In such a use case, the complex number is no longer POD, and moving to the property model with (now nontrivial) getters and setters becomes more sensible.