• OK, it's on.
  • Please note that many, many Email Addresses used for spam, are not accepted at registration. Select a respectable Free email.
  • Done now. Domine miserere nobis.

Programming Woes

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Do you ever try to write a program (as in, on a computer), and then it gets so damn big that you can barely keep up with what you've got?

Or maybe you understand it all in your head, but when you start getting run-time errors it's pretty much impossible to fix it without screwing something somewhere else up? And even if you can fix it this way, it takes hours and hours, maybe even days, since you have to go through and change things around all over the program, and eventually you end up getting lost with all the changes you've made and having to reload a previous version and start over?

Or you just get so fed up with it that you decide to scrap a month's worth of work and like 10,000 lines of code and start over from scratch because it actually seems easier due to all of the above difficulties? Or you take a break from what you're writing for a few months and when you come back you have no idea what the heck is going on in there anymore?

I'm wondering if this is something that goes away with more experience, or if there is simply a limit to how much complexity a person can hold in their head at once, or if I'm possibly just stupid and a really shitty programmer. From having repeated this process of building something, watching it become more and more complex until making any changes requires a Herculean effort, and then eventually just giving up and starting over, I've decided I need to find a new strategy here. So far my best ideas are:


:eek: Actually diagram out what I'm trying to build before I start coding it, instead of taking the "I'm smart, I can just start writing and juggle it in my head as I go" approach. Problem: I don't know enough about software engineering to know if what I'm flowcharting or describing will actually work before I type it in and hit the compile button.

:eek: Read that damn "Code Complete" book front to back, preferably memorizing every page, until it teaches me all the tricks that people use to overcome these difficulties. Problem: It would take a really long time and I'd likely move on to something else and never actually get anything useful built.

:eek: Break everything up into really, really, really small functions (maybe 12-15 lines of code), and use very long, descriptive names for variables and functions, so that when you go back to change things it doesn't just look like a big mass of meaningless gibberish. Problem: I don't know if this will actually make it easier, or just waste more time.

:eek: Keep practicing and hope I get smarter/more experienced. Problem: It will also take a really long time and may never happen.

:eek: Make a really long post on INTPforum seeing if anyone else can relate to this issue. Problem: This isn't really a programming forum.


So does anyone else have any stories about the aneurism-inducing stressfulness of trying to create software? Or perhaps advice on how real software developers manage to write massively complex programs without driving themselves insane or giving themselves strokes in the process? Needless to say, I can't even imagine how people actually manage to do this stuff in teams, but I'm sure they must be using a vastly different process than whatever I'm doing.

/rant
 

menaceh2k

Member
Local time
Today 10:22 AM
Joined
Jan 28, 2010
Messages
69
---
Location
Philadelphia
yeah lol :storks: I know the feeling. What language are you using? comments comments comments..i hope you are commenting like hell...you might see everything clearly as you are programing, but :( go to something else or move away from your work for a few days or a weeks, when you come back to it, you might be like WTF. So commenting is a must.



http://www.devtopics.com/13-tips-to-comment-your-code/
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
If you decide to do #3, which I think is a good idea (in moderation, at least) to avoid the catastrophic widespread bugs that are slowing you down, I highly recommend using a functional programming language. This is especially true if this is solitary hacking, because functional languages are used less than the industry standards of C, C++, Java, Python, Perl, and Ruby, not necessarily in that order. I say this because the standard idiom of functional languages is breaking things up into small functions and then stringing together your small functions, and they put in features that make this easier to implement and more powerful to use as well.

The example I'd suggest is Haskell, though if what you're doing is speed-intensive, a Common Lisp such as CMUCL or SBCL may be a better option. CMUCL and SBCL compete with C in speed (that is, sometimes they are faster, sometimes slower, though in general they are probably a little slower) when they are compiled (they can also be interpreted), while Haskell is probably a few times slower than C when compiled (it can also be interpreted). If you're interested in more detail, say so here or PM me.
 

Cognisant

cackling in the trenches
Local time
Today 4:22 AM
Joined
Dec 12, 2009
Messages
11,155
---
Go back to basics imo.

The problem with code is that there's never "near enough", either it works or you've fucked it up, the computer never fucks it up, so if it's not working and the problem's not obvious then its more than likely:
1. A syntax error.
2. Mixed up values.
3. Processes occurring out of order.

Y'know the really basic stuff, because that's the stuff that's really hard to find when you've made a mistake and they're the really easy mistakes to make because you falsely believe they're too obvious to make. So yeah go back to basics, really focus on the little things, treat yourself like an idiot until you've learnt the craftsmanship of code, the technique, not the actual how-to knowlage which you already have.

And read this.
http://www.canonical.org/~kragen/tao-of-programming.html
 

dark

Bring this savage back home.
Local time
Today 10:22 AM
Joined
Sep 19, 2010
Messages
901
---
Back in highschool when I started programming things I had this problem, I started out with the calculator programs, and to solve this problem I started breaking down my programs into many programs, keeping everything running off of something else, and each small function had its own program, I think this ends up using more space, but it allowed my programs to run much smoother and have less errors due to my ignorance. When I started learning/teaching myself C and Basic, I used the same things I learned, now when something happens, and goes wrong I usually know exactly where I went wrong, so correction was really quick. But I don't think I have ever wrote anything this complicated as you mentioned, 100 lines per program were almost a max for me. Simple things doing simple things while the more complexity was comprised with the masses, etc. But I haven't tried programming in about 6 years... my last programming effort/success was when a friend of mine had a regular xbox to fail something to do with an update messing up the entire hdd data, so I spent 2 days messing around the directories and rewriting things according to my own xbox, getting into the damn thing after it locked itself was the hardest thing, Probably spent about 1 of the days messing with a linux dos type thing, trying to break into the hdd, but how I even got to that stage of the deal, I can't even remember, I just remember typing shit loads of commands on my linux system before I started, compiled a dvd program and booted the damn thing up to my dvd, it was writing the boot disc that took me the most time. Maybe I should get back into doing this stuff, but I would have to learn almost every bit of it again, hell I don't even remember how to use my calculator programs anymore haha.
 

walfin

Democrazy
Local time
Today 11:22 PM
Joined
Mar 3, 2008
Messages
2,436
---
Location
/dev/null
Melllvar said:
Or you just get so fed up with it that you decide to scrap a month's worth of work and like 10,000 lines of code and start over from scratch because it actually seems easier due to all of the above difficulties?
What exactly are you doing?

Seems easier doesn't mean always easier, you may end up coding another framework that you thought would take away all your woes, only to find yourselves plugging away at the debugger yet again. Then you would've merely succeeded in wasting a lot of time.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Hm, I actually got responses. Been busy with other stuff today so I haven't had time to work on it anymore, unfortunately. It sounds like in general my problems are a bit of "all of the above." Let me explain a little more if you guys are actually curious.


Language
: C++. Although I'm definitely going to look into Haskell, possibly the others too, if for no other reason than I need to learn new stuff. I checked out some of the haskell.org and book.haskell.org sites last night. Long story short, pretty cool stuff (I'm totally unfamiliar with functional programming).

Program: Essentially something to teach foreign language vocabulary. I started it about a year ago on the premise that it only takes one to a few thousand of the most common words to be able to converse fairly well in a language, so if you can easily memorize, oh, maybe 10,000 words, you'll already have a huge head start on being multi-lingual. Memorizing the words is trivial compared to pronunciation, grammar, etc., but that first "memorizing thousands of words" part is what you have to do before you can really start getting into the other stuff. More than just a simple vocab quiz, the program would also data-mine your previous lessons to find optimal learning strategies for the user, and would use some other tricks I came up with to hopefully get the upper hand on other stuff that's already commonly in use (I don't want to give all my best ideas away right here on the forum though :D).

Basic program structure (this is the basic overview, not every single detail): I made objects to store all words and necessary data about them. Then I stored all those objects/words in vectors (just for now, no point optimizing it for the best data structure before I even know what all it's going to be doing calculation-wise). I was actually using pointers for almost everything so that words could point to other words, could be rearranged on the fly, and I wouldn't need to have a bunch of copies of the same objects, since the program would already require tens of thousands of objects per language to store all the words/versions of words/etc (that would have wasted a lot of storage capacity).

Latest Problem: So I wanted to have vectors of pointers to different kinds of objects (for example, a pointer to a spanish verb object and a pointer to a swahili noun object in the same vector). So I made one class, then derived all the classes I wanted from it, and made a vector of pointers to the parent class. Then I could shove all the derived classes into the same vector. Problem was that since it was technically a vector of pointers to the parent class, I couldn't use all the different members and methods that were defined in the child classes.

Solution: I decided to just give up on the idea of deriving classes from the parent class, and simply have one class with lots and lots of members and methods that could work for any word in any language. I hadn't wanted to do this originally since there would be so many of these objects (specifically, one for every single spelling of a word in every language I would be working with), that I wanted to keep the objects as small as possible to save space. However, just for the sake of getting it working, I decided to just do it the "simpler" way.

The real problem: Now, normally changing this kind of thing wouldn't be that hard, I do it all the time. But since the program was already so large and complicated, going back and rewriting the entire thing to work with an entirely different class instead of all the little derived classes turned out to be incredibly hard. Once I got rid of all the compiler errors (that was actually really easy), the program was still crashing because of run-time errors, and by that time I had changed so much that it was hard to remember what else was part of the original version and what had already been changed. For all I knew I was recreated classes that were already being used because I'd forgotten they were in some other part of the program.

:storks:

My real issue is how to deal with large, complex programs. I can sit there and troubleshoot most issues until I fix them (one way or the other), but it doesn't help once the program gets beyond a level where I can really keep up with what's going on in more than 10% of the program all at once. Even if I found a way to make this program simpler, or came up with a better structure for it that didn't have these problems, this whole issue would still creep up again on some other even bigger, more complicated program.


As for comments, I have decided that over-use is better than under-use. That's mainly because I did most of the work on this program about 4-6 months ago, and when I started on it again this week it took me at least two full days to refamiliarize myself with how it worked. So yeah, I've definitely started commenting the heck out of my code.

Most of the functions are also fairly small, since I already realized that for some reason having a lot of little functions makes it easier to understand than a few really big functions (still not really sure why though). Most of the trouble I was having yesterday occurred in the still-fairly-big functions, which is part of why I'm thinking that might be what's causing me so much trouble. In the future: definitely smaller functions and classes.


Also, so this isn't just the "help Melllvar with his program thread," feel free to share your own stories of horrible troubles you've had writing software. :p
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>

Can't say I got a lot of tangible knowledge out of that, but I'm definitely gonna re-read it next time I get fed up with what I'm working on.

A manager asked a programmer how long it would take him to finish the program on which he was working. "It will be finished tomorrow,'' the programmer promptly replied.

"I think you are being unrealistic,'' said the manager, "Truthfully, how long will it take?''

The programmer thought for a moment. "I have some features that I wish to add. This will take at least two weeks,'' he finally said.

"Even that is too much to expect,'' insisted the manager, "I will be satisfied if you simply tell me when the program is complete.''

The programmer agreed to this.

Several years later, the manager retired. On the way to his retirement luncheon, he discovered the programmer asleep at his terminal. He had been programming all night.
I'm pretty sure that's a parable for my entire experience with this particular thing.

A master programmer passed a novice programmer one day. The master noted the novice's preoccupation with a hand-held computer game. "Excuse me,'' he said, "may I examine it?''

The novice bolted to attention and handed the device to the master. "I see that the device claims to have three levels of play: Easy, Medium, and Hard,'' said the master. "Yet every such device has another level of play, where the device seeks not to conquer the human, nor to be conquered by the human.''

"Pray, great master,'' implored the novice, "how does one find this mysterious setting?''

The master dropped the device to the ground and crushed it underfoot. And suddenly the novice was enlightened.
That also gave me some interesting stuff to think about in relation to game design.

my last programming effort/success was when a friend of mine had a regular xbox to fail something to do with an update messing up the entire hdd data, so I spent 2 days messing around the directories and rewriting things according to my own xbox, getting into the damn thing after it locked itself was the hardest thing, Probably spent about 1 of the days messing with a linux dos type thing, trying to break into the hdd, but how I even got to that stage of the deal, I can't even remember, I just remember typing shit loads of commands on my linux system before I started, compiled a dvd program and booted the damn thing up to my dvd, it was writing the boot disc that took me the most time.

That sounds really complicated (to me). 99% of the stuff I've ever written was just straight programs in C++, all in the console. I was looking into the Windows API a few weeks ago but decided to go back to this thing instead, and it seemed terribly complicated anyway. Working with pre-existing code/software is something new to me (w/ the exception of a few game engines, and a little OpenGL). I'd have no idea how to do any of what you're talking about.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Alas, I have been foiled. The compiler wins again. For now.

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>

using namespace std;

class Parent {};

class Child1 : public Parent {
public:
string string1;

Child1() {string1 = "This is the string in child1!\n";}
};

class Child2 : public Parent {
public:
string string2;

Child2() {string2 = "This is the string in child2!\n";}
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;
vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << vector[0]->string1;
cout << vector[1]->string2;
delete child1;
delete child2;

return 0;
}

C:\Documents and Settings\temp>g++ experiment.cpp -o main.exe
experiment.cpp: In function `int main()':
experiment.cpp:30: error: 'class Parent' has no member named 'string1'
experiment.cpp:31: error: 'class Parent' has no member named 'string2'

This shall require further thought.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Victory!

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>

using namespace std;

class Parent {};

class Child1 : public Parent {
public:
string string1;

Child1() {string1 = "This is the string in child1!\n";}
};

class Child2 : public Parent {
public:
string string2;

Child2() {string2 = "This is the string in child2!\n";}
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;
vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << ((Child1*)vector[0])->string1;
cout << ((Child2*)vector[1])->string2;

delete child1;
delete child2;

return 0;
}

C:\Documents and Settings\temp>main.exe
This is the string in child1!
This is the string in child2!

Now if only I had thought of that right away instead of wasting all of Tuesday trying to rewrite the entire thing.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
Why are you using C++, by the way? I'm pretty strongly biased against it for most applications that don't absolutely need it (for example, game design). But even if I try to ignore that bias I can't see what you're doing that makes C++ seem like the best choice, unless you're doing it at least partly to learn C++ for subsequent work (and since you're writing something quite large, I doubt that).
 

5k17

suspective
Local time
Today 4:22 PM
Joined
May 17, 2010
Messages
183
---
Location
Germany
Why are you using C++, by the way?
You might as well ask why one breathes when they can have an iron lung do that for them. C++ is pure awesomeness.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
You might as well ask why one breathes when they can have an iron lung do that for them. C++ is pure awesomeness.
What have you coded in?
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Why are you using C++, by the way? I'm pretty strongly biased against it for most applications that don't absolutely need it (for example, game design). But even if I try to ignore that bias I can't see what you're doing that makes C++ seem like the best choice, unless you're doing it at least partly to learn C++ for subsequent work (and since you're writing something quite large, I doubt that).

*thinks*

Ah, yes, that language is good for domain specific solutions, but it doesn't adequately address the issue of multiple inheritance out of the box.

Seriously though, there isn't a real reason. C++ was the first language I started messing with, and still the only one I have any proficiency with (if you can call it that, as my above posts demonstrate). Seeing as how I've already got a lot of stuff done in it, it seems easier to keep doing it this way, rather than rewriting it all in a language I don't know very well. A previous version of this translation program was already running, this is in fact version 2 since the way I structured it the first time wasn't going to allow for much robustness with all the features I wanted to add. The fact that it supposedly runs fast and is so widely used has only been more incentive to keep learning C++ better instead of writing a full program in something else.

I am interested in learning other stuff though. In fact I kind of need to before I get too rigidly used to this one language. I'd messed around a little with Python, Lisp and Java already (and Haskell briefly the other night), but every time I decide to do anything like this it's always a question between learning an entirely new language before I even get started, or making quick progress in the language I already know.
 

Saeros

Destroyer of Worlds
Local time
Tomorrow 2:22 AM
Joined
Feb 20, 2010
Messages
244
---
Location
Inside my head.
Very cool idea for a program. Do you have any particular language in mind for the vocabulary? Also, from where are you planning on getting the vocabulary? It would take you quite a while to get 10,000 words organized, wouldn't it? Will the program include a translation for the vocabulary? in which language? how will you store that information.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Ideally I'd cover all languages. For testing purposes I'm working with spanish right now, since I know more of it than any other. At the very least I should be able to easily do all the other major romance languages, and I don't see any reason I couldn't manage most that have romanized alphabets. Moving to non-romanized alphabets will be a whole other thing, but that's still a ways off. I've been using lists of translated words I copied out of websites, all pasted into .txt documents. When I inevitably run into a language I can't do this with, or for words that are very uncommon and not available this way, I've thought about using google translate. Then I could hopefully automate it to where the program searches through ebooks/webpages, stores words it doesn't recognize, and then uses gTranslate or something else to figure out what they mean.

I would like to have it be a full "language engine" eventually, capable of translation, generating (grammatically correct) random sentences, etc. Theoretically I'd eventually try to incorporate natural language processing and AI techniques. But I can't say it'll actually get that far. For now I'd just be happy to be able to teach and quiz vocabulary between any two languages that are stored in it.

There's also the idea that as it finds patterns in people's learning strategies, it could send the info back to me and I might be able to learn new stuff about how people learn/think (cognitive psychology and whatnot). But again, small steps for now.
 

5k17

suspective
Local time
Today 4:22 PM
Joined
May 17, 2010
Messages
183
---
Location
Germany
What have you coded in?
So far, I've mainly coded in Game Maker Language, C++, and Java (yuck). I also know, but seldom use Turbo Pascal, RuneScript (scripting language for an RPG called RuneSword), and Brainfuck. My studies of other languages (Perl, Python, Ruby, BASIC, and various esolangs) have been rather short (because I did not really find any of them both intriguing and usable), so I only know some bits and pieces about those.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
So far, I've mainly coded in Game Maker Language, C++, and Java (yuck). I also know, but seldom use Turbo Pascal, RuneScript (scripting language for an RPG called RuneSword), and Brainfuck. My studies of other languages (Perl, Python, Ruby, BASIC, and various esolangs) have been rather short (because I did not really find any of them both intriguing and usable), so I only know some bits and pieces about those.
Yeah, you kinda lack a frame of reference then, imo. C++ is massive, has far too many things not integrated together in it, and has almost all the annoying aspects of C. It has speed going for it and it has some abstraction going for it over C, and that's honestly about all it DOES have going for it. You are considerably better off, imo, working in a high level language and calling C functions from a high level language if speed is necessary, than working in C++, for most applications. (Game design isn't the ONLY exception, but I'd probably call it the only really blatant exception.)
 

pjoa09

dopaminergic
Local time
Today 10:22 PM
Joined
Feb 9, 2010
Messages
1,857
---
Location
th
why dont you just keep on checking if that code is alright? i am a very big newbie but i do that all the time. sometimes Visual C++ fucks me. with its debugging bullshit so i figure ways out but other than that i think now they are good but too good or actually bad.. whenever i forget something they tell me before hand like the semi-colon.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
Victory!

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>

using namespace std;

class Parent {};

class Child1 : public Parent {
public:
string string1;

Child1() {string1 = "This is the string in child1!\n";}
};

class Child2 : public Parent {
public:
string string2;

Child2() {string2 = "This is the string in child2!\n";}
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;
vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << ((Child1*)vector[0])->string1;
cout << ((Child2*)vector[1])->string2;

delete child1;
delete child2;

return 0;
}

C:\Documents and Settings\temp>main.exe
This is the string in child1!
This is the string in child2!

Now if only I had thought of that right away instead of wasting all of Tuesday trying to rewrite the entire thing.

First, you shouldn't be accessing data in the class directly, you should only use methods. Data always should be private or protected in classes.

Second, I think you have object-oriented design confused. Inheritance is not used this way. In a base class, you should define the methods that you want all derived classes to have. Then you should define the methods that are modiable for the derived classes to modify, these are virtual methods.

The reason behind inheritance is that you want to be able to reuse the codes in the base classes and not have to rewrite the entire thing in the derived classes, you only want to change the things that need to be changed in the derived classes.

The way that you're using inheritance is very convoluted because you can always make the instances of the child classes to be void pointers and then cast them to be Child1* or Child2* if you are doing it your way.

The correct way to use inheritance is to define a virtual function in the base class so your derived classes can modify them.

Here is the correct way to use inheritane
#include <vector>
#include <cstdlib>
#include <string>
#include <iostream>

using namespace std;

class Parent
{
public:
Parent() { }
virtual string get_str() = 0; //Virtual function that the child classes will use.
};

class Child1 : public Parent
{
public:
Child1() {string1 = "This is the string in child1!\n";}
string get_str() {return string1;} //Modifying get_str() from parent

private:
string string1;
};

class Child2 : public Parent
{
public:
Child2() {string2 = "This is the string in child2!\n";}
string get_str() {return string2;} //Modifying get_str() from parent.

private:
string string2;
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;
vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << vector[0]->get_str(); //No casting here, using it as if it's Parent*
cout << vector[1]->get_str(); //No casting here, using it as if it's Parent
*
delete child1;
delete child2;

return 0;
}
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
C++ is massive, has far too many things not integrated together in it, and has almost all the annoying aspects of C. It has speed going for it and it has some abstraction going for it over C, and that's honestly about all it DOES have going for it. You are considerably better off, imo, working in a high level language and calling C functions from a high level language if speed is necessary, than working in C++, for most applications. (Game design isn't the ONLY exception, but I'd probably call it the only really blatant exception.)

Not to waste your time, but do you have any more detail about this? As in, what sort of tools do functional languages/high-level languages give you to make it easier than C++? I've always tended to assume it was all about the same, as long as you knew the ins and outs of whatever language you were using. Obviously that isn't completely true, but there's enough people who are gung-ho for all the big languages that it's hard to believe any one is really particularly better, except for perhaps specific purposes, C++ for games like you mentioned (I assume because of the speed thing).

pjoa09 said:
why dont you just keep on checking if that code is alright? i am a very big newbie but i do that all the time. sometimes Visual C++ fucks me. with its debugging bullshit so i figure ways out but other than that i think now they are good but too good or actually bad.. whenever i forget something they tell me before hand like the semi-colon.

That's what I usually do, just trial and error it until I figure out something that works (it's what I did above in fact, just wrote a smaller program to try and find a solution to the basic problem). But once the program gets really big it's too complicated to keep changing things around every time you run into a problem. First of all it's confusing as heck, which leads to more bugs, and second of all it takes way way waaay too long once the program gets past a certain size.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
First, you shouldn't be accessing data in the class directly, you should only use methods. Data always should be private or protected in classes.

Yeah, I know that part, but for dealing with problems leaving them public in the beginning helps to keep the program small until I'm done dealing with the little issues. I frequently have to rewrite/reorganize the classes as I run into new problems, and it takes a lot more time to rewrite all the functions to access private members everytime I realize "oh heck, that isn't what I need, I need this instead." For example, I just realized I didn't need to have separate boolean variables to specify which language the user was working in, I could just have one enumerated one. If I had made it private already I would have wasted all that time writing functions to access multiple variables that I now realize I don't even need.

So I usually leave them public when starting out, then make them private once I've got everything the way I want it.

Second, I think you have object-oriented design confused. Inheritance is not used this way. In a base class, you should define the methods that you want all derived classes to have. Then you should define the methods that are modiable for the derived classes to modify, these are virtual methods.

The reason behind inheritance is that you want to be able to reuse the codes in the base classes and not have to rewrite the entire thing in the derived classes, you only want to change the things that need to be changed in the derived classes.

The way that you're using inheritance is very convoluted because you can always make the instances of the child classes to be void pointers and then cast them to be Child1* or Child2* if you are doing it your way.

The correct way to use inheritance is to define a virtual function in the base class so your derived classes can modify them.

Here is the correct way to use inheritane
#include <vector>
#include <cstdlib>
#include <string>
#include <iostream>

using namespace std;

class Parent
{
public:
Parent() { }
virtual string get_str() = 0; //Virtual function that the child classes will use.
};

class Child1 : public Parent
{
public:
Child1() {string1 = "This is the string in child1!\n";}
string get_str() {return string1;} //Modifying get_str() from parent

private:
string string1;
};

class Child2 : public Parent
{
public:
Child2() {string2 = "This is the string in child2!\n";}
string get_str() {return string2;} //Modifying get_str() from parent.

private:
string string2;
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;
vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << vector[0]->get_str(); //No casting here, using it as if it's Parent*
cout << vector[1]->get_str(); //No casting here, using it as if it's Parent
*
delete child1;
delete child2;

return 0;
}

Thanks! This is very useful info. I'll definitely try it today and make sure it all works the way I'm understanding it. This should allow the classes to be simpler also, since the way I was doing it I think I would have needed more members and long switch/if branches just to specify which type I should cast it too.

Part of the disadvantage of being self-taught is there's no one to correct you when you're doing stupid stuff like that. Although I did take some CS classes in college, and no one there ever gave me any useful info like this either. They just treated me like an idiot if I didn't already know it.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Eh, didn't actually help as much as I had hoped, since I'm actually trying to access different types of variables in the derived classes, and C++ apparently doesn't have much support for overloading by return type.

This example is a lot closer to my actual program (it doesn't compile):
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>

using namespace std;

struct A {};
struct B : A {string str;};
struct C : A {string str;};

class Parent {
public:
virtual A* get_struct() {};
};

class Child1 : public Parent {
private:
B structB;

public:
Child1() {structB.str = "This is the string in B!\n";}
B* get_struct() {return &structB;};
};

class Child2 : public Parent {
private:
C structC;

public:
Child2() {structC.str = "This is the string in C!\n";}
C* get_struct() {return &structC;};
};

int main() {
Child1 *child1 = new Child1;
Child2 *child2 = new Child2;

vector<Parent *> vector;
vector.push_back(child1);
vector.push_back(child2);
cout << vector[0]->get_struct()->str;
cout << vector[1]->get_struct()->str;

delete child1;
delete child2;
vector.clear();
system("PAUSE");
return 0;
}
C:\Documents and Settings\temp>g++ experiment.cpp -o main.exe
experiment.cpp: In function `int main()':
experiment.cpp:42: error: 'struct A' has no member named 'str'
experiment.cpp:43: error: 'struct A' has no member named 'str'
I can think of at least three ways around this, but it's gonna take some time to figure out what I should really be doing instead.

Edit: Nevermind, I just made them classes instead of structs and did the same thing The Journey showed me w/ virtual functions.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
Not to waste your time, but do you have any more detail about this? As in, what sort of tools do functional languages/high-level languages give you to make it easier than C++? I've always tended to assume it was all about the same, as long as you knew the ins and outs of whatever language you were using. Obviously that isn't completely true, but there's enough people who are gung-ho for all the big languages that it's hard to believe any one is really particularly better, except for perhaps specific purposes, C++ for games like you mentioned (I assume because of the speed thing).
C++ is good for game design because you need the speed and simultaneously don't have the time to build up all the infrastructure you need yourself, which is what you would probably need to do if you were working in C.

As for easier things:
  • No pointers. Good for everything except systems programming.
  • Having quite a bit already done for you. One very good example of this is Python, which has a very extensive standard library. Having this organized in a good way is also very helpful. By what I understand, this organization is one of the biggest issues with C++ in particular (that is, as opposed to similar languages, not as opposed to languages in general).
  • In functional languages, higher order functions. You can work out how your functions get used, and write additional functions that take those functions as arguments. This can be simulated using function pointers in C(++) but it is very awkward and infrequently used. This is more useful than you might think.
  • In Haskell at least, pattern matching. That is, you can define a function's behavior with different arguments based on patterns in the variables. An example is:
    map f [] = []
    map f (x:xs) = (f x):(map f xs)
    This is two lines of pattern matching. The way it works is, if the first line pattern matches, then you get its output, if not you move to the second, etc. What this actually says is that if the second argument is an empty list, return an empty list. Otherwise, if the second argument is a list of the form (x:xs) (which is a list whose head is x and whose tail is xs), return a list whose head is (f x) (f applied to x) and whose tail is (map f xs). An example of this in action is:
    map (+1) [1,2,3] = [2,3,4]
  • In functional languages, side effects of functions are in general obvious. That is, something in the way the language works makes it obvious that your function does something other than just return a value and/or returns something different with the same arguments. The way this works depends on the language. In Scheme (one of the two main forks of Lisp) side effects are generally brought about using operators that make it fairly obvious that side effects are occurring. In Scheme these operators end in a !. In Haskell, any side effects have to be done using a significantly different portion of the language in general.

    What this means is that your function does what you think it does, basically, and nothing else. This makes debugging much simpler, although at times it makes the original coding task more difficult.
  • Continuing in the vein of virtual functions as The Journey mentioned, Haskell has typeclasses. These are classes of types. A type can be an instance of a typeclass if and only if it defines all the functions that the typeclass requires. A nice thing about this in Haskell is that since functions are essentially ordinary values, and since the language is also statically typed, functions have types, which means that in typeclass definitions you can define functions only by specifying their type, without having to specify anything about what they actually do. The standard library does this a LOT.
  • In Lisps, there is an extensive macro system which essentially allows you to rather freely extend the syntax of the language. This is so broad that it's honestly kinda hard to characterize why it's a good thing.

This is sort of a survey; there's definitely more to be said still.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
From experience, the only things that would make me prefer a language over another is the library that the language has and how stable the language is.

Speed should never matter in choosing a programming language, using speed to judge a language is very unreasonable given computers speed nowadays. A program speed is determined by so many variables to the point that the effect of a programming language is rarely felt. The only two things that would really affect a program's speed would be the program's design and the bugs in the program, which are totally independent of the programming language.

As for functional vs. imperative, it's really just preference. I wouldn't buy into the hype of functional programming language until you actually used it to create non-trivial programs.

I personally prefer C++ because it is more familiar and because of the examples and books that are available.

There are really no bad programming language, only bad programmers.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
From experience, the only things that would make me prefer a language over another is the library that the language has and how stable the language is.

Speed should never matter in choosing a programming language, using speed to judge a language is very unreasonable given computers speed nowadays. A program speed is determined by so many variables to the point that the effect of a programming language is rarely felt. The only two things that would really affect a program's speed would be the program's design and the bugs in the program, which are totally independent of the programming language.

As for functional vs. imperative, it's really just preference. I wouldn't buy into the hype of functional programming language until you actually used it to create non-trivial programs.

I personally prefer C++ because it is more familiar and because of the examples and books that are available.

There are really no bad programming language, only bad programmers.
If there are no bad programming languages, then what are esolangs? Surely Brainfuck is "bad" for actual use. Thus to say without justification that no languages are bad is not valid, so the scale is there. It's a fuzzy scale, but it's still a scale. COBOL, for a nontrivial example, is bad, without a doubt.

As for speed: no. Just no. Language choice can lead to order-of-magnitude changes in performance. Sometimes being 10x slower or more than equivalent C code isn't cutting it. A lot of the time it is, though.

As for languages: I'd make the same argument about saying that it's just preference, to be honest. Don't draw any conclusions about one being better or even both being equal until you've given both a shot, but definitely DO give both a shot. (I say this mainly because asserting "it's just preference" and being believed tends to lead people in the direction of staying with what they know/have, in my experience.) I'll say though that almost everything I've ever read about good programming style, even in imperative languages, has pretty much been functional style, verbatim. Maybe not going as far as using higher order functions, but for example splitting the problem into lots of small functions and having your functions essentially return their value and mostly do nothing else are rather functional ideas.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
If there are no bad programming languages, then what are esolangs? Surely Brainfuck is "bad" for actual use. Thus to say without justification that no languages are bad is not valid, so the scale is there. It's a fuzzy scale, but it's still a scale. COBOL, for a nontrivial example, is bad, without a doubt.

I guess my point is that a programmer's design and the correctness of the program is much more important than a programming language.

As for speed: no. Just no. Language choice can lead to order-of-magnitude changes in performance. Sometimes being 10x slower or more than equivalent C code isn't cutting it. A lot of the time it is, though.

I would like to know the language that you are refering to.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
I guess my point is that a programmer's design and the correctness of the program is much more important than a programming language.
When the program's done, sure; when the program's done, assuming it is actually 100% done, no bugs etc., the only contribution of the language is to speed. The language is more important while you're actually coding.

I would like to know the language that you are refering to.
Python is one of many examples that are much much slower than C. It's pretty easy to find benchmarks for languages like these. (Don't get me wrong, I like Python. Speed is just not one of its strong suits.)
 

walfin

Democrazy
Local time
Today 11:22 PM
Joined
Mar 3, 2008
Messages
2,436
---
Location
/dev/null
Hi Melllvar, why didn't you use dynamic_cast<>?

BTW, your static cast (in the original) is a very dangerous thing to do. Especially if the classes have different sizes and you are using arrays.

In any case, the use of virtual functions in that way requires very good planning and top-down design. Your base class has to envisage all (well at least many) possibilities. What if you forget something? Then you may have to modify the base class and if you add variables you screw up all the binary files that you wrote. Unless, of course, everything can be done by calling a virtual doSomething() in the base class.
 

pjoa09

dopaminergic
Local time
Today 10:22 PM
Joined
Feb 9, 2010
Messages
1,857
---
Location
th
PYTHON FTW! but i just hate having to paste and indent so much then they went 3.0 and I am stuck there standing like I was just getting a hold man!!
 

₲uardian

Eccentric Stranger
Local time
Today 10:22 AM
Joined
Aug 15, 2010
Messages
93
---
programming aint just about writing code. It's about writing code you can maintain as well as many other aspects that make your product successful and delivered in a timely fashion. With programming, you dont realize how much further you can go. You might think you're awesome now, but the learning never ends.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
I've really dropped the ball on this forum. Actually I got so caught up trying to write this damn program it's kind of consumed my life the past week or so. I haven't really done much else, but let me take the time to dish out some replies:

C++ is good for game design because you need the speed and simultaneously don't have the time to build up all the infrastructure you need yourself, which is what you would probably need to do if you were working in C.

As for easier things:
  • No pointers. Good for everything except systems programming.
  • Having quite a bit already done for you. One very good example of this is Python, which has a very extensive standard library. Having this organized in a good way is also very helpful. By what I understand, this organization is one of the biggest issues with C++ in particular (that is, as opposed to similar languages, not as opposed to languages in general).
  • In functional languages, higher order functions. You can work out how your functions get used, and write additional functions that take those functions as arguments. This can be simulated using function pointers in C(++) but it is very awkward and infrequently used. This is more useful than you might think.
  • In Haskell at least, pattern matching. That is, you can define a function's behavior with different arguments based on patterns in the variables. An example is:
    map f [] = []
    map f (x:xs) = (f x):(map f xs)
    This is two lines of pattern matching. The way it works is, if the first line pattern matches, then you get its output, if not you move to the second, etc. What this actually says is that if the second argument is an empty list, return an empty list. Otherwise, if the second argument is a list of the form (x:xs) (which is a list whose head is x and whose tail is xs), return a list whose head is (f x) (f applied to x) and whose tail is (map f xs). An example of this in action is:
    map (+1) [1,2,3] = [2,3,4]
  • In functional languages, side effects of functions are in general obvious. That is, something in the way the language works makes it obvious that your function does something other than just return a value and/or returns something different with the same arguments. The way this works depends on the language. In Scheme (one of the two main forks of Lisp) side effects are generally brought about using operators that make it fairly obvious that side effects are occurring. In Scheme these operators end in a !. In Haskell, any side effects have to be done using a significantly different portion of the language in general.

    What this means is that your function does what you think it does, basically, and nothing else. This makes debugging much simpler, although at times it makes the original coding task more difficult.
  • Continuing in the vein of virtual functions as The Journey mentioned, Haskell has typeclasses. These are classes of types. A type can be an instance of a typeclass if and only if it defines all the functions that the typeclass requires. A nice thing about this in Haskell is that since functions are essentially ordinary values, and since the language is also statically typed, functions have types, which means that in typeclass definitions you can define functions only by specifying their type, without having to specify anything about what they actually do. The standard library does this a LOT.
  • In Lisps, there is an extensive macro system which essentially allows you to rather freely extend the syntax of the language. This is so broad that it's honestly kinda hard to characterize why it's a good thing.
This is sort of a survey; there's definitely more to be said still.

I'd be lying if I said I understood all that 100%. Pattern matching sounds like a more implicit form of branching, but I may be misunderstanding it. As for extensive libraries, I wasn't really aware that the C++ Standard Library (or whatever it's called) was any less extensive than others, or poorly organized. The weirdest part of that is the "no pointers" thing. It's kind of hard to imagine life without them at this point. From what I'd read of Haskell so far the most appealing thing was overloading by return type, which would have been really, really, really useful a couple of times so far. Although, considering I've used pointers to most everything in this program, I'm not sure that switching to a language without them wouldn't require to me completely rethink how I'm doing everything.

In any case, I think I'll bump these up on my list of "computer things to learn next" based on how different they sound. As is probably obvious by now I'm not that experienced at this and trying to write a large, complicated program is partially my way of learning more about it (also I want to learn foreign languages). Right now I'm getting to the point where I want to just hurry up and get this thing to a minimally working level so I can move on to something else, since it's becoming obvious that I don't have nearly the programming knowledge/skillz to handle what I'm trying to do. Instead of continuing this one thing until it has all these nifty features, I think I'll just get it working as a basic vocab quiz thing (along with a few languages and sorting based on which words you need the most work on) and then move on to other languages, APIs, and general software design, with the goal of hopefully making the next project much easier. Otherwise I feel like I'm going to waste a lot of time writing crappy code when I could spend the time furthering my knowledge of the subject, which would more productive in the long run.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Hi Melllvar, why didn't you use dynamic_cast<>?

BTW, your static cast (in the original) is a very dangerous thing to do. Especially if the classes have different sizes and you are using arrays.

In any case, the use of virtual functions in that way requires very good planning and top-down design. Your base class has to envisage all (well at least many) possibilities. What if you forget something? Then you may have to modify the base class and if you add variables you screw up all the binary files that you wrote. Unless, of course, everything can be done by calling a virtual doSomething() in the base class.

To be honest I'm not that familiar with the different cast versions. Whenever I've used it I just did the standard (type) cast. I wasn't even aware you could cast to user-defined types until I tried it in the above example. I'll have to read up on that when I get to a better stopping point with this particular project.

For the record, I've actually most rewritten the entire thing now into much smaller functions, which has helped in keeping track of what's going on. Not knowing what I'm really doing, and without any kind of plan to follow, I think I'm just going to stop every once in a while and go through the code I've written, reorganizing it and simplifying it so that it's easier to keep up with (which would hopefully solve the original 'complexity' problem I was having). As a side affect of that, I pretty much did away with the derived classes and virtual functions, and settled for just having larger, unrelated classes.

When I get more time I'll probably write a bunch of smaller programs to experiment with all this stuff, as there's still a lot I don't know about even basic C++. Having self-taught it to myself four or five years ago, and then not touched it until I decided to start this up about a year ago, I didn't bother to go back and reread every page of the book, and had completely forgotten about things like virtual functions or dynamic_cast (if I ever knew about it at all).

Hey, I never claimed to know what I was doing. I just said I was trying to write a program that had gotten really big and unwieldy, and wondered how other people dealt with such issues. This is largely a "learn as I go" kind of thing.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
programming aint just about writing code. It's about writing code you can maintain as well as many other aspects that make your product successful and delivered in a timely fashion. With programming, you dont realize how much further you can go. You might think you're awesome now, but the learning never ends.

Don't worry, I have no illusions of being awesome at this. In fact, I kind of figure the program size and complexity of it is a side affect of being an almost complete noob to this sort of thing. But I think I already covered my ignorance level in the previous posts.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
I'd be lying if I said I understood all that 100%. Pattern matching sounds like a more implicit form of branching, but I may be misunderstanding it.
Pattern matching parses to a case statement, if that helps, but it's easier to write and read than an explicit case statement. I should've clarified that "map" (the example I used) iterates through a list of elements, and applies the function to each of them.
As for extensive libraries, I wasn't really aware that the C++ Standard Library (or whatever it's called) was any less extensive than others, or poorly organized.
I think it's more the vast swath of different libraries that you would draw from in a typical project (this being a key point; you actually need them to stay efficient) that are too numerous to be well-organized. I may drag Wisp in here to properly explain this point.
From what I'd read of Haskell so far the most appealing thing was overloading by return type, which would have been really, really, really useful a couple of times so far.
I'm not sure what exactly overloading by return type is, having not dealt with a language that actually uses the concept of "overloading" directly (I've heard the term and have a general idea what it means, but I haven't "grokked" it).

I know Haskell has a system that is used to implement what some other languages call "overloading", which is typeclasses; you make a type an instance of a typeclass that defines a function, and you can call that function on your type. In the typeclass definition, the function may be fully defined, it could be simply given a type, or it could be defined in terms of other functions which are themselves simply given a type. Outside typeclass definitions you can also define functions which can act on or return any types that are instances of one or more typeclasses; for a trivial example, you can define functions that will take and return numbers of any type.

As for pointers: I honestly can't see why you would WANT pointers for a task that isn't systems programming. Can you give an example of something nontrivial (not like making an array or whatever) that you've done with pointers, and what it does?
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
I'm not sure what exactly overloading by return type is, having not dealt with a language that actually uses the concept of "overloading" directly (I've heard the term and have a general idea what it means, but I haven't "grokked" it).

I know Haskell has a system that is used to implement what some other languages call "overloading", which is typeclasses; you make a type an instance of a typeclass that defines a function, and you can call that function on your type. In the typeclass definition, the function may be fully defined, it could be simply given a type, or it could be defined in terms of other functions which are themselves simply given a type. Outside typeclass definitions you can also define functions which can act on or return any types that are instances of one or more typeclasses; for a trivial example, you can define functions that will take and return numbers of any type.

This sounds like the basic idea then. Overloading is just having several functions with the same name, but taking different parameters, and the compiler/language figures out which one your calling based on what parameters you passed. So for example:

int function(float myfloat);
int function(double mydouble);

Then if you use the function you can pass it either a float or a double and it will somehow figure out which one you want.

In the case of overloading by return type, for me it would have been useful to do something like this:

SpanishVerb GetVerb();
EnglishVerb GetVerb();

Then I could just do things like:

mySpanishVerb = GetVerb();
myEnglishVerb = GetVerb();

and the language would sort out which function I wanted by itself. Unfortunately I can't seem to do that in C++. Not that at it matters anymore because I'm past that point anyway.

As for pointers: I honestly can't see why you would WANT pointers for a task that isn't systems programming. Can you give an example of something nontrivial (not like making an array or whatever) that you've done with pointers, and what it does?

Actually pointers were one of those things I avoided using for as long as I could until I finally forced myself to start using, and now I kind of like them. I'm not sure that they're absolutely necessary, but I'd mainly be using them for situations like:

class SpanishVerb {... lots and lots of stuff ...};
vector<SpanishVerb> allMySpanishVerbs;
vector<SpanishVerb *> someSpanishVerbs;
vector<SpanishVerb *> differentSpanishVerbs;
vector<SpanishVerb *> thirdSubsetOfSpanishVerbs;
etc...

This way I don't have to have a lot of copies of large objects, I just have pointers to the original objects in the first vector. I'm assuming the pointer is a much smaller variable since it only holds the address, so it saves space to not have many copies of the same objects, and now if I want to change something in one of those objects I can change it once and don't have to change every copy of it in every data structure.

Also, when I took a data structures class in college, we implemented a lot of the sorting and list type features using pointers. For example, the data structure might be a bunch of objects, with each one having a pointer that points to the next object in the structure. If you want to delete something, you just tell the pointer of the object before it to point to the next object after it, then get rid of the one in the middle, and the "list" of objects is now missing the one you deleted.

So I kind of wonder how other languages handle these issues without using pointers. I kind of figured they were a necessary part of all programming languages.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
Why would you have vectors of pointers that are pointed to other data in another container?

That is just scary to just look at, A LOT of errors waiting to happen.

1: Unless your computer or your targeted clients computers have really small memory constraints, you shouldn't be using pointers that way to "increase efficiency". You should really only use vector<SpanishVerb>, it will not affect the program much, unless SpanishVerb is a overly complex and excessively huge class.

2: If you still want to do it that way, don't use pointers, you should be looking at using a bidirectional_map of integers and SpanishVerbs. So you can then have a vector<int> to access a subset of the original SpanishVerbs, using vector<SpanishVerb *> of pointers pointing to another container is very dangerous and ill-advised.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
The reason was that I needed to essentially be able to pick random words out of a subgroup with different qualities (for example, does the user want to be tested on all nouns, or nouns and verbs, or the 30 whatevers they've most frequently missed, etc.). It seemed there were two ways to do that, a) pick a random one and see if it has the desired qualities, and if not keep picking until we get one that does, or b) generate a list of all the words with the desired qualities, then pick from it. I chose the latter since the number of items that matched might be small compared to the entire dictionary, so it would prevent having to randomly choose a word thousands of times before we found one that matched.

There's probably another (simpler) way to do this that I haven't thought of, but honestly I didn't see anything so dangerous about it. In actuality all the containers would be of pointers to objects, and since they're pointing to the address of the actual object, not to the position in the container, I didn't think that reorganizing them would screw up the pointers. Maybe I'm wrong about that.

It has occurred to me recently that I'm probably wasting a lot of time and effort trying to keep things smaller than necessary, since nothing I'm writing is likely to be that memory or computation intensive, and if it turns out to be I can worry about it then. On the other hand though, trying to do things in new ways has at least taught me more about it, like trying to use derived classes and virtual functions and such.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
You should always avoid using pointers if you're using C++.

For example, if the original vector were to be somehow deleted either by out-of-scope or other methods, the remaining vectors will contain pointers that point to nowhere.

If you are using pointers merely to increase efficieny, then when you try to delete, change, or insert a new SpanishVerb into the original vector (not at the end), the pointers in vector<SpanishVerb *> will again contain pointers that are useless. Say original_vec[0] contains X, and let's say subset_vec[0] = &original_vec[0], which is what you are saying you want to do. Now subset_vec[0] points to X, when you dereference it, the value will be X. Now let's say somewhere along the line the original vector is changed, now original_vector[0] contains Y. Now when you derefence subset_vec[0], the value will no longer be X, it will be Y. The function that was using subset_vec will have no knowledge of this change because the operation was done on the original_vec, not subset_vec. If this was the behavior that you wanted, it is tedious and error-prone to keep track of the pointers and the values that you really want them to be pointed to.

The better and less error-prone way is to simply let the subset vectors contain SpanishVerb instances of their own. That way you can change the original_vec and the subset_vec and do not have to worry if changing one will cause the other to change. This leads to simpler and easier to read code and you don't have to spend 3 hours debugging a simple mistake that could have been prevented easily.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
This sounds like the basic idea then. Overloading is just having several functions with the same name, but taking different parameters, and the compiler/language figures out which one your calling based on what parameters you passed. So for example:

int function(float myfloat);
int function(double mydouble);

Then if you use the function you can pass it either a float or a double and it will somehow figure out which one you want.

In the case of overloading by return type, for me it would have been useful to do something like this:

SpanishVerb GetVerb();
EnglishVerb GetVerb();

Then I could just do things like:

mySpanishVerb = GetVerb();
myEnglishVerb = GetVerb();

and the language would sort out which function I wanted by itself. Unfortunately I can't seem to do that in C++. Not that at it matters anymore because I'm past that point anyway.
You probably wouldn't explicitly do it that way, exactly, in Haskell. In particular, although you can assign types to things like this, you usually don't need or even really want to. In Haskell I'd have:
class Verb where
getVerb = stuff
morestuff

data SpanishVerb = <stuff>

instance Verb SpanishVerb where
getVerb = stuff
morestuff

data EnglishVerb = <stuff>

instance Verb EnglishVerb where
getVerb = stuff
morestuff

(I'm not gonna bother doing the indentation correctly, but suffice it to say that that won't compile as is for a variety of reasons).

Then when I call getVerb, most likely if I need it to be one or the other, something that I do with the output will force it to be one or the other. Then the compiler will kick in and decide what it is (at compile time). If that isn't necessary, then at runtime it can take either kind of argument.

Actually pointers were one of those things I avoided using for as long as I could until I finally forced myself to start using, and now I kind of like them. I'm not sure that they're absolutely necessary, but I'd mainly be using them for situations like:

class SpanishVerb {... lots and lots of stuff ...};
vector<SpanishVerb> allMySpanishVerbs;
vector<SpanishVerb *> someSpanishVerbs;
vector<SpanishVerb *> differentSpanishVerbs;
vector<SpanishVerb *> thirdSubsetOfSpanishVerbs;
etc...

This way I don't have to have a lot of copies of large objects, I just have pointers to the original objects in the first vector. I'm assuming the pointer is a much smaller variable since it only holds the address, so it saves space to not have many copies of the same objects, and now if I want to change something in one of those objects I can change it once and don't have to change every copy of it in every data structure.

Also, when I took a data structures class in college, we implemented a lot of the sorting and list type features using pointers. For example, the data structure might be a bunch of objects, with each one having a pointer that points to the next object in the structure. If you want to delete something, you just tell the pointer of the object before it to point to the next object after it, then get rid of the one in the middle, and the "list" of objects is now missing the one you deleted.

So I kind of wonder how other languages handle these issues without using pointers. I kind of figured they were a necessary part of all programming languages.
That depends. Haskell doesn't have mutable state for the most part, and so you don't in general do in-place update. You can, technically, and in some applications you might want to, but it isn't automatic, and the way that you do it is sort of isolated from the rest of the language. Other languages will do in-place update in different ways without explicitly needing pointers.

Even by what little I know about pointers though, it sounds like you're overusing them.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
If you are using pointers merely to increase efficieny, then when you try to delete, change, or insert a new SpanishVerb into the original vector (not at the end), the pointers in vector<SpanishVerb *> will again contain pointers that are useless. Say original_vec[0] contains X, and let's say subset_vec[0] = &original_vec[0], which is what you are saying you want to do. Now subset_vec[0] points to X, when you dereference it, the value will be X. Now let's say somewhere along the line the original vector is changed, now original_vector[0] contains Y. Now when you derefence subset_vec[0], the value will no longer be X, it will be Y.

Actually, it seems that isn't what will happen, because I just tried it:

#include <iostream>
#include <vector>

using namespace std;

class Experiment{
public:
string str;
};

int main() {
vector<Experiment *> expVec;
vector<Experiment *> secondVec;
vector<Experiment *>::iterator it;

expVec.push_back(new Experiment);
expVec.push_back(new Experiment);

secondVec.resize(2);
secondVec[0] = expVec[0];
secondVec[1] = expVec[1];

expVec[0]->str = "string 1";
expVec[1]->str = "string 2";
Experiment *myExperiment = new Experiment;

cout << "Printing two strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << endl;

cout << "Now inserting into the first element of expVec.\n";
it = expVec.begin();
expVec.insert(it, myExperiment);
expVec[0]->str = "string 0";

cout << "Printing three strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << " " << expVec[2]->str << endl;
cout << "Printing the second two strings from expVec, through their pointers in secondVec: ";
cout << secondVec[0]->str << " " << secondVec[1]->str << endl;

for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.clear();
for(int i = 0; i < secondVec.size(); ++i) {
delete secondVec;
secondVec = 0;
}
secondVec.clear();

system("PAUSE");
return 0;
}


Output:

Printing two strings from expVec: string 1 string 2
Now inserting into the first element of expVec.
Printing three strings from expVec: string 0 string 1 string 2
Printing the second two strings from expVec, through their pointers in secondVec: string 1 string 2
Press any key to continue . . .

I hope that isn't too unreadable.

It seems I was originally correct; the pointers are pointing to the object's address in memory, not to its position in the vector. So inserting at the beginning of the vector doesn't screw up the pointers in the other vector, as the program shows.

I do remember something about inserting screwing up pointers, but I think that was for iterators, if you try to insert at an earlier position while having an iterator pointing to some position in the vector. I can't remember exactly for sure, but by what you're saying the above program shouldn't print "string 1 string 2" at the end.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Yep, just tried it with iterators, and it crashes when it tries to dereference the iterator after the insert (but not before), but it can still dereference the pointers that were set equal to the other pointers in the first vector:

#include <iostream>
#include <vector>

using namespace std;

class Experiment{
public:
string str;
};

int main() {
vector<Experiment *> expVec;
vector<Experiment *> secondVec;
vector<Experiment *>::iterator it;

expVec.push_back(new Experiment);
expVec.push_back(new Experiment);

secondVec.resize(2);
secondVec[0] = expVec[0];
secondVec[1] = expVec[1];

expVec[0]->str = "string 1";
expVec[1]->str = "string 2";
Experiment *myExperiment = new Experiment;

cout << "Printing two strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << endl;

it = expVec.begin();
cout << endl << "String in position pointed to by iterator (before insert): " << (*it)->str << endl << endl;

cout << "Now inserting into the first element of expVec.\n" << endl;
expVec.insert(it, myExperiment);
expVec[0]->str = "string 0";

cout << "Printing three strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << " " << expVec[2]->str << endl;
cout << "Printing the second two strings from expVec, through their pointers in secondVec: ";
cout << secondVec[0]->str << " " << secondVec[1]->str << endl;
cout << endl << "String in position pointed to by iterator (after insert): " << (*it)->str << endl;;

for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.clear();
for(int i = 0; i < secondVec.size(); ++i) {
delete secondVec;
secondVec = 0;
}
secondVec.clear();

system("PAUSE");
return 0;
}


Although I think what you're saying about not using pointers is still probably valid, since (as I just learned reading) iterators are necessary for looping through other data structures (besides vectors), and if I decide to change the vectors to something else, it would require me to both rewrite everything using iterators, and then the same problem you mentioned would creep up with insert/delete/etc.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
Actually, it seems that isn't what will happen, because I just tried it:

#include <iostream>
#include <vector>

using namespace std;

class Experiment{
public:
string str;
};

int main() {
vector<Experiment *> expVec;
vector<Experiment *> secondVec;
vector<Experiment *>::iterator it;

expVec.push_back(new Experiment);
expVec.push_back(new Experiment);

secondVec.resize(2);
secondVec[0] = expVec[0];
secondVec[1] = expVec[1];

expVec[0]->str = "string 1";
expVec[1]->str = "string 2";
Experiment *myExperiment = new Experiment;

cout << "Printing two strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << endl;

cout << "Now inserting into the first element of expVec.\n";
it = expVec.begin();
expVec.insert(it, myExperiment);
expVec[0]->str = "string 0";

cout << "Printing three strings from expVec: ";
cout << expVec[0]->str << " " << expVec[1]->str << " " << expVec[2]->str << endl;
cout << "Printing the second two strings from expVec, through their pointers in secondVec: ";
cout << secondVec[0]->str << " " << secondVec[1]->str << endl;

for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.clear();
for(int i = 0; i < secondVec.size(); ++i) {
delete secondVec;
secondVec = 0;
}
secondVec.clear();

system("PAUSE");
return 0;
}



What you are doing is more dangerous. You now have potentially two vectors of pointers pointing to exactly same memory locations with these lines.

secondVec[0] = expVec[0];
secondVec[1] = expVec[1];

So when you try to do this:

for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.clear();
for(int i = 0; i < secondVec.size(); ++i) {
delete secondVec;
secondVec = 0;
}
secondVec.clear();


With expVec and secondVec or any other indexes containing pointers pointing to the exact memory location, you are telling the computer to (1) go to heap and go to the memory location as pointed to by expVec, delete the object then (2) go to the exact same memory location on the heap pointed by secondVec again and delete the "Experiment" object that is apparently still in there, which it obviously is not.

I'm truly shocked that apparently this example ran without runtime errors left and right for you. Try to compile and run the example again, I think you might be surprised.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
You are making trivial codes more complicated and unneededly obsfucated by using pointers.

Trust me, take my advice and use vectors of separately initialized objects.

If for some reasons you need to update the derived vectors, just do it with the following format of a function or method.

void update_vec(vector<Object>::iterator iter_begin,
vector<Object>::iterator iter_end) {

for (vector<Object>::iterator iter = iter_begin; iter != iter_end;
++iter) {
*iter = //Whatever you want here;
}

}

If you do it via pointers, the derived vectors are updated implicitly, causes unneeded code complexity, and takes unwieldly amount of time writing correct initialization codes and deletion codes.

If you have vectors with initialized objects, you can update explicitly, the code is very simple (as the case above), and you don't have to worry about writing correct initialization or deletion codes.

Programming is about writing clear, concise, and correct codes. Speed or efficieny should be done using correct algorithms and designs and should NEVER be done with using esoteric language features like pointers.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Yeah, I noticed that, but since nothing was going wrong I figured an extraneous delete command didn't particularly matter. Maybe I should double check on that. :slashnew:

Actually, I tried it multiple times on two different computers (both with the GCC compiler), and even tried calling delete twice on the same objects in the same vector. No run-time or compile-time errors that I can tell.

#include <iostream>
#include <vector>

using namespace std;

class Experiment{
public:
string str;
};

int main() {
vector<Experiment *> expVec;
vector<Experiment *>::iterator it;

expVec.push_back(new Experiment);
expVec.push_back(new Experiment);
Experiment *myExperiment = new Experiment;
it = expVec.begin();
expVec.insert(it, myExperiment);

cout << "expVec.size() = " << expVec.size() << endl;
for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
cout << "expVec.size() = " << expVec.size() << endl;
for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.push_back(new Experiment);
cout << "expVec.size() = " << expVec.size() << endl;
delete expVec[3];
expVec[3] = 0;
expVec.clear();

system("PAUSE");
return 0;
}
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
Yeah, I noticed that, but since nothing was going wrong I figured an extraneous delete command didn't particularly matter. Maybe I should double check on that. :slashnew:

Actually, I tried it multiple times on two different computers (both with the GCC compiler), and even tried calling delete twice on the same objects in the same vector. No run-time or compile-time errors that I can tell.

#include <iostream>
#include <vector>

using namespace std;

class Experiment{
public:
string str;
};

int main() {
vector<Experiment *> expVec;
vector<Experiment *>::iterator it;

expVec.push_back(new Experiment);
expVec.push_back(new Experiment);
Experiment *myExperiment = new Experiment;
it = expVec.begin();
expVec.insert(it, myExperiment);

cout << "expVec.size() = " << expVec.size() << endl;
for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
cout << "expVec.size() = " << expVec.size() << endl;
for(int i = 0; i < expVec.size(); ++i) {
delete expVec;
expVec = 0;
}
expVec.push_back(new Experiment);
cout << "expVec.size() = " << expVec.size() << endl;
delete expVec[3];
expVec[3] = 0;
expVec.clear();

system("PAUSE");
return 0;
}


The reason that this works without a problem because after every delete, you are setting expVec to be NULL, and calling a delete on a NULL does nothing. Take out the line expVec = 0 and you will be in for a surprise :)

The previous example was not the same, you were deleting two vectors in which both had pointers pointing to the same location on the heap, setting expVec = NULL will not have the same effect as in this example when you do delete secondVec because the value of secondVec is not NULL, so you will get a runtime error.
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Sorry, was in the middle of writing that post when you made your last. Tbh I still don't really see what is, in and of itself, wrong with making complex code that is faster or more efficient (i.e. using "esoteric language features"), other than a trade-off of making it harder for anyone else that might come along and try to work on it, but since this method seems to only work with certain containers (e.g. vectors), and would make it hard to change it later, I'd already planned to switch to a non-pointer version.

I'm still not sure why the behavior is different than you're saying it should be though. My guess would be that some compilers know not to call delete if they don't need to, or else double calling it is harmless.

Edit: This is probably one of those things I'm not supposed to say, but honestly for very small programs, does calling delete even matter? I'm pretty sure you get the memory back when the program quits running, it's not like it's lost from the computer forever (I think), so the only real risk is that the program eventually runs out of memory and crashes.
 

The Journey

Redshirt
Local time
Today 3:22 PM
Joined
Apr 10, 2010
Messages
21
---
Sorry, was in the middle of writing that post when you made your last. Tbh I still don't really see what is, in and of itself, wrong with making complex code that is faster or more efficient (i.e. using "esoteric language features"), other than a trade-off of making it harder for anyone else that might come along and try to work on it, but since this method seems to only work with certain containers (e.g. vectors), and would make it hard to change it later, I'd already planned to switch to a non-pointer version.

I'm still not sure why the behavior is different than you're saying it should be though. My guess would be that some compilers know not to call delete if they don't need to, or else double calling it is harmless.

We are talking about fractional improvements, 1 or 2 miliseconds at best, if there are any improvements at all.

When you write more complex programs, the two things that will matter most is (1) the design of the program and (2) the algorithms it uses.

Pointers are an archaic legacy of low-level languages. Almost all languages now do not have them. Languages that have them have a lot of restrictions such as using only as references and etc...
 

Melllvar

Banned
Local time
Today 9:22 AM
Joined
Mar 17, 2010
Messages
1,269
---
Location
<ψ|x|ψ>
Well, scratch that last part then, if pointers are really that outdated I'm not going to bother learning all the subtle nuances of delete.

Actually, I did finally get it give some errors, which required making the first vector, filling it with strings, setting the second vector equal, deleting the first vector without setting it equal to null, and then trying to print the strings through the second vector. This resulted in a bunch of weird symbols in addition to the actual strings. Anything less than that and I couldn't get an error.

I'd have just pasted the output, but it's hard to copy n' paste from the console. Nevertheless, you were correct, thanks for the help. :)

Edit: Actually, I think that may just have been because I deleted the same objects I'm trying to dereference, which makes me wonder why the strings printed at all. In any case, I'm done with this for a while. I still have to rewrite the entire actual program to not use pointers.
 

Latro

Well-Known Member
Local time
Today 10:22 AM
Joined
Apr 18, 2009
Messages
755
---
We are talking about fractional improvements, 1 or 2 miliseconds at best, if there are any improvements at all.

When you write more complex programs, the two things that will matter most is (1) the design of the program and (2) the algorithms it uses.

Pointers are an archaic legacy of low-level languages. Almost all languages now do not have them. Languages that have them have a lot of restrictions such as using only as references and etc...
Don't take this too far. FFTW is an extremely good example of a program that NEEDS that speed because of what it does.
 
Top Bottom