Page 11 of 13

Re: Advice for novice programmers thread

Posted: Wed May 05, 2021 9:39 pm
by Seasoft
ECMA/JavaScript sounds like a lame idea for a //first language.

Re: Advice for novice programmers thread

Posted: Wed May 05, 2021 9:46 pm
by nullplan
Seasoft wrote:ECMA/JavaScript sounds like a lame idea for a //first language.
What an utterly well-reasoned and constructive opinion. Would you care to expand upon that or are you just here to insult people? (Hint: The tone makes the music.)

Re: Advice for novice programmers thread

Posted: Thu May 06, 2021 5:56 am
by vvaltchev
I believe it makes sense starting with a mainstream typed language such as Java, C or C++.
But none of them is perfect as a first language (nor perfect per se, of course).

* The problem with Java is that allows just one paradigm (object-oriented programming) and doesn't teach much about how stuff works under the hood. It's the standard choice for many introduction-level college courses. I'd describe that as a "safe but limited road".

* The problem with C++ is that, while is all-powerful, is too complicated and expert-friendly to start with. So, you can give the students the illusion that you can create a with "vector<int> vec" and just append elements, like you can do in Java with an ArrayList, but very soon, they'll started to get confused and have a ton of problems with complex error messages and "weird" crashes because they don't really understand pointers, manual memory management, what means "invalidating an iterator" etc. And that's the basic stuff. Let's not even mention things like move semantics.
Starting with directly C++ might work for somebody but it's, IMHO, like walking a "dangerous road".

* The problem with C is that has very poor abstractions, but teaches very well how "stuff works". Is a good language to start with, but after getting confident with it, it's mandatory learning a 2nd higher-level language as well. So, starting with C is great, but it's really the "longest road".

Re: Advice for novice programmers thread

Posted: Tue Jul 13, 2021 10:55 pm
by MrPsycho
I have a question. And though this might be another dumb one that question is this:

Is there any advice for older/more retro programming languages? For example 1964's BASIC

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 1:51 am
by Solar
vvaltchev wrote:* The problem with C++ is that, while is all-powerful, is too complicated and expert-friendly to start with.
The problem with C++ is that it requires a really good instructor. Done right, you can get all the way through an introduction course and halfway into an intermediate course without even mentioning pointers, or indeed arrays. And today, "manual memory management" is something for library implementors, if even that. Unless you are programming an allocator, you should never have to write "new" or "delete".

C++ suffers, to this day, from most people approaching it from the C side of things. Taught as a first language, without going through C null-terminated char arrays, pointers, malloc / free etc., it works surprisingly well. I've taught several beginners, both kids and adults, and the less they knew about C the easier it was.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 5:16 am
by vvaltchev
Solar wrote:The problem with C++ is that it requires a really good instructor. Done right, you can get all the way through an introduction course and halfway into an intermediate course without even mentioning pointers, or indeed arrays. And today, "manual memory management" is something for library implementors, if even that. Unless you are programming an allocator, you should never have to write "new" or "delete".
That's the modern mainstream approach towards teaching C++, pushed by most C++ evangelists and by Stroustrup himself. I oppose this approach, despite its high-profile advocates. It's all about teaching modern C++ AS IF it was a managed language like Java or C#. It goes like: "use vector<T>, map<T>, make_unique(), make_shared(), etc. follow the _rules_ and it will work". The problem with that is: what happens when we do make a mistake? In managed languages, mistakes have a much limited effect compared to unmanaged ones. Null pointer? Exception. Out of bounds? Exception. Use after free / double free? Cannot have that with GC. Uninitialized memory? There's no such thing in managed languages I know.

So, while by following the rules beginners can kind of survive with C++ initially, my experience shows that, at some point, sooner or later, they always hit an "impossible bug": something happened that shouldn't be possible in their view. And they cannot debug the program, because debugging requires a level of understanding of what happens under the hood that they don't have at all. UB due to invalidated iterators or buffer overflow are good examples. And what about race-conditions? When it's explained where the bug is and how it happened, everybody is able to understand it, but when it's about using a debugger to dig in the "raw" memory trying to understand what happened, people who have been taught C++ in such a way have no idea what to do. It's worth remarking that such bugs are NOT a rare, but happen pretty often. The more junior the dev is, the more kind of such bugs she/he will produce. To me, it's necessary to prepare people to debug their own code. Note: even if we talk just about printf/cout debugging, the problem remains: if order to investigate the problem you need some understanding of what might have happened. Knowing that buffer overflow is UB and that UB means "anything can happen" doesn't help in practice: you have to be aware that, in many cases, the nearby variables will be overwritten etc. In other cases, well... compilers will take advantage of that and.. good luck!

In conclusion, the idea that C++ can be treated almost as a "managed" language by using STL or Boost, without a decedent level of understanding about happens under the hood, looks to me like as a fragile house of cards, without a solid base. It makes people believe they "know C++" while they don't know even 10% of it. Maybe C++ evangelists push forward that approach because they don't realize how much they are biased by their knowledge and wisdom when writing examples of "simple modern C++". In other words, "simplicity is the ultimate sophistication".

Said that, I don't claim that the modern approach towards teaching C++ never works. (I claim that it won't work for many people well-enough.) I believe that for some exceptionally talented people, who can learn and almost flawlessly follow an incredible complex set of rules in a very limited time (1 year?), it will work pretty good. Those people might have enough imagination for debugging problems given just the theory from their CS degree about how operating systems and programs work together, without years and years of practice. But... for most of people, I'd believe that walking down the "long road" going through completely manual memory management is the safest and the most natural way of learning "modern C++". In other words: first, learn how to walk, then learn how to run and only then, finally, learn how to fly.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 6:01 am
by nexos
Solar wrote:The problem with C++ is that it requires a really good instructor. Done right, you can get all the way through an introduction course and halfway into an intermediate course without even mentioning pointers, or indeed arrays. And today, "manual memory management" is something for library implementors, if even that. Unless you are programming an allocator, you should never have to write "new" or "delete".
The thing is maximum power is what has brought people to C/C++ for decades! If I want a memory safe language, I'll use Java or Rust. I like old fashioned C++, and quite honestly, I greatly dislike C++11 and later. The reason why is because they are trying to hide what has C++ has thrived on! C++ is trying to become a safe language, but, it has become a bloated mess instead!

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 10:18 am
by nullplan
Solar wrote:The problem with C++ is that it requires a really good instructor.
That is very true. Same goes for C. C really only started clicking for me when I joined a Usenet group discussing the subject, and the standard came up (frequently). I had previously never heard of ISO C, but immersing myself in the subject really helped my C. And then I went to Uni afterwards, enrolled in CS, and got a Programming professor that did not care one lick about portable code, and basically wrote C like he had learned to do in Turbo C for DOS. Teaching tons of wrong things. Thankfully I only had to endure it for half a semester, but I can't imagine the damage a more impressionable mind would take on such upbringing.

And my C++ really got a lot better when I started listening to talks at CppCon. I still don't like C++, but I'm at least proficient in it. One of the most important things was the notion that ca. 80% of the language only exists for compatibility reasons. E.g. there's typedef and using, and the latter allows you to do everything the former does, and then some. So when teaching it, you can basically just skip typedef entirely. And that sort of thing is everywhere in C++. Ranged-for, Iterators, "auto", ...

And then I come back to work where I have to work with a C++98 compiler that uses a prelinker (if you never have to learn what that is, you will die a happier person than I am), and suddenly the idea of C++ is a lot less appealing.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 12:27 pm
by vvaltchev
Well yeah, CppCon is much better for learning C++ than most academic courses. I like it too and I've learned a ton of stuff from it. While I disagree with their message about how C++ is easy to teach etc., that's doesn't mean their lessons aren't worth listening. I've learned a ton of advanced stuff from there. I don't believe CppCon is the right place for C++ absolute beginners to start with, but in order to jump from medium to advanced level and past that, I'd totally recommend it, along with a serious amount of real-world practice in big C++ projects. CppCon is for me the "goto place" when I'd like to learn about the newest language features, patterns, tools, traps & pitfalls etc.

With C++, I have a love-hate relationship. In particular, I love the new features and I find them very useful. If I had to write some C++ code, I would never be happy to go back using any standard older than C++17. But.. that doesn't mean I like the way C++ is taught and used today. The same language, with the same features can used very well or very poorly. The sad truth according to my own view is that most of the C++ code is bad, because it's written by people who don't understand it "well enough" and who want to treat it like a managed language, which is not. C++ allows you to "stop thinking" about a ton of stuff and that leads to bad code IMHO. Tools have to be used carefully. E.g. it's good to have shared_ptr<T> but you cannot use it everywhere without thinking about the price you're paying for retain/release cycles. Even unique_ptr<T> is not exactly for free. The same applies for templates: they're all-powerful but beware of the price you're paying for that: in some cases by touching a common header, you could add +1 MB in code size to the big project you're working on. Is your change really worth that price? Good engineers balance carefully between runtime and compile-time. Making everything that could be a template parameter to actually be is not always the right choice. Good C++ engineers can anticipate the kind of machine code that will be generated and often do reality checks to check their expectations. While saying to people "don't worry, trust the compiler" is pretty bad IMHO. You have to worry most of the time. Otherwise, is better to write in Java and get an ultra optimized GC + JIT instead trying to do the things natively, with a "lazy" attitude. Paradoxically, poor C++ code which needlessly creates, copies and destroys heap-allocated objects could perform slowly as Java itself or even worse than it, because of the lack of JIT.

EDIT: fix typo "how" -> "who" plus other minor fixes to make the text flow better.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 4:22 pm
by Solar
vvaltchev wrote:That's the modern mainstream approach towards teaching C++, pushed by most C++ evangelists and by Stroustrup himself. I oppose this approach, despite its high-profile advocates. It's all about teaching modern C++ AS IF it was a managed language like Java or C#. It goes like: "use vector<T>, map<T>, make_unique(), make_shared(), etc. follow the _rules_ and it will work". The problem with that is: what happens when we do make a mistake? In managed languages, mistakes have a much limited effect compared to unmanaged ones. Null pointer? Exception. Out of bounds? Exception. Use after free / double free? Cannot have that with GC. Uninitialized memory? There's no such thing in managed languages I know.
Java can have dangling references, or unreachable objects still referenced, leading to resource leaks. Java claims it is free of pointers, but does throw a literal NullPointerException on occasion. You have a String object that might not actually be a String object because it is actually NULL pointers? In its way, Java is more backward than C++. And it's not without pointers, it is all pointers, it's just lying through its teeth about it.

C++ can be used as a language without manual memory management, without C arrays, and yes, to a large degree without using pointers. And you know what? Your code will be shorter, more expressive, and more robust that way.

And, actually, easier to debug. Because you are not mucking about with C constructs.

I recommend Stop Teaching C by Kate Gregory, making the point much better than I could: Showing "the C way", especially at the beginning, means your students will pick up a lot of bad habits early on, be overwhelmed by lots of itty bitty details, and then have to unlearn / relearn everything when getting to idiomatic C++. This is what resulted in so many people being stuck halfway between C and idiomatic C++, and blaming C++ for being "hard". Only a fraction ever got to real C++, and despair a bit every time the "C++ is hard" argument comes up. Going from C to C++ in tiny steps is hard. Starting with C++, the real C++ taught by an instructor who knows that all the C stuff is for backward compatibility only -- that is such an easy learning experience you wouldn't believe it.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 6:12 pm
by vvaltchev
Solar wrote:Java can have dangling references, or unreachable objects still referenced, leading to resource leaks.
As far as I know, that's not possible unless you mess with JNI or use weird things like sun.misc.unsafe#allocateMemory().
https://stackoverflow.com/questions/497 ... using-java

Can you show me how to do that in pure Java?
Solar wrote:Java claims it is free of pointers, but does throw a literal NullPointerException on occasion. You have a String object that might not actually be a String object because it is actually NULL pointers? In its way, Java is more backward than C++. And it's not without pointers, it is all pointers, it's just lying through its teeth about it.
Nobody talking about Java has ever hidden the fact that all objects are pointers. Having NULL pointers is absolutely natural a concept for most programming languages. It's not a defect. Forcing an object to always have a value is bad, and would also lead to many limitations. How could you create a linked list? You cannot have an infinite amount of objects. Having a NULL "next" pointer is exactly what we want. Null pointers are absolutely simple to use in Java and the rest of managed languages. No UB, nothing. Just, you obviously cannot attempt to de-reference it. But if you do, you'll get a clear exception, no surprises.
Solar wrote:C++ can be used as a language without manual memory management, without C arrays, and yes, to a large degree without using pointers. And you know what? Your code will be shorter, more expressive, and more robust that way.
I disagree, but I just wanna let go. Answering here would lead to an endless discussion like the one about the history of UB in C. We'll be both happier by just skipping this. Obviously, we're light years apart and there's no way to change that.
Solar wrote:Going from C to C++ in tiny steps is hard.
And it's, IMHO, the right way to learn C++. Obviously, things can be skipped along the way. For example? Well, the classic "auto" that nobody used, along with auto_ptr<T> and a bunch of other stuff that has been replaced by better features. No need to know the limitations of C++11's lambdas. No need to know C++11's limitations of constexpr etc. The long way to learn C++ does not include learning each C++ standard. It's all about exploring all the features of the latest standard, step by step.
Solar wrote:Starting with C++, the real C++ taught by an instructor who knows that all the C stuff is for backward compatibility only -- that is such an easy learning experience you wouldn't believe it.
Oh.. I believe that such path will be easy for people, while they learn. The problem is they won't know/understand a ton of super important stuff and will be very limited in what can do in terms of practical stuff. And they will suffer when they hit non-trivial problems.

Anyway, I'm forcing myself to stop here. No intention in fighting another war. I've expressed my opinion, you have expressed yours, that's enough. Readers will make up their own mind.

Re: Advice for novice programmers thread

Posted: Wed Jul 14, 2021 10:23 pm
by nullplan
vvaltchev wrote:How could you create a linked list?
With interfaces.

Code: Select all

public class List<T> {
  interface Node {
    bool isEnd();
    Node getNext();
    T getVal();
  }
  private Node first;
  class EmptyNode implements Node {
    EmptyNode() {}
    bool isEnd() { return true; }
    Node getNext() { throw new NotImplementedException(); }
    T getVal() { throw new NotImplementedException(); }
  }
  class FullNode implements Node {
    private Node n;
    private T val;
    FullNode(T v, Node nx) { n = nx; val = v; }
    bool isEnd() { return false; }
    Node getNext() { return n; }
    T getVal() { return val; }
  }
  class ListIterator implements Iterator {
    private Node n;
    ListIterator(Node node) { n = node; }
    bool hasNext() { return !n.isEmpty(); }
    T next() {
      T val = n.getVal();
      n = n.getNext();
      return val;
    }
  }
  List() { first = new EmptyNode(); }
  void PushFront(T v) { first = new FullNode(v, first); }
  Iterator iterator() { return new ListIterator(first); }
}
Excuse syntax errors in the above code, I haven't done this in a while. In any case, as you can see, not a single null reference is present or desired. Object oriented programming allows you to do things very differently from pure procedural programming. I do not think having all references be nullable is a good thing. In C++, references are never NULL. There is a separate type to denote the possibility for an object to not be filled (called Nullable, similar to Haskell's Maybe), and so you cannot pass a reference that may be NULL to a function that can't deal with it.

Using the type system to detect such errors is one of the hallmarks of higher level programming, so it is a bit of a shame to see people not take advantage of it. In C, I have started using small structs all over the place to keep several low-level things apart from each other. I have a struct for 4-byte little endian values, and 4-byte big endian values, and functions to translate between those and actual integers. I never have to deal with byte swapping ever again!

Re: Advice for novice programmers thread

Posted: Thu Jul 15, 2021 2:42 am
by Solar
vvaltchev wrote:Anyway, I'm forcing myself to stop here. No intention in fighting another war. I've expressed my opinion, you have expressed yours, that's enough. Readers will make up their own mind.
It's not a war; it really isn't, not for me. This is relaxed chat, for me. If it isn't for you, sorry, and this is my last post on the matter as well.

This is something I have experience in, and if you and I had the time (I don't, though, sorry) I'd love to show you what I mean in practice. I completely understand your POV, I've been there not that long ago myself. I even started an online blog series to teach C++ "ground up", "oldschool", which was how I learned it myself after all.

Which was exactly when I realized how many problems you create that way.
Nobody talking about Java has ever hidden the fact that all objects are pointers. Having NULL pointers is absolutely natural a concept for most programming languages. It's not a defect.
Not a defect, but a crutch, dating back to a time when pointers were all we had. You don't need pointers when you can have references -- which, incidentially, can never be NULL. References are simply superior to pointers in every conceivable way.
How could you create a linked list? You cannot have an infinite amount of objects. Having a NULL "next" pointer is exactly what we want.
See? You think "linked list", and immediately think about its innards, about the "next pointer" in there. I think "linked list" and immediately know that that's a standard container I can just use.

Thinking about innards, thus breaking the abstraction, is exactly the kind of thinking that perpetuates problem of people approaching C++ bottom-up. It absolutely does not matter how a linked list works internally, because we have a complete implementation available.

Code: Select all

my_class x{ 42 };
std::forward_list< my_class > list;
list.push_back( x );
The point being, you don't have to talk about "next" pointers, and / or null. You don't have to talk about how you used to code a linked list in C, or how you would implement a linked list in C++ if there weren't one. You need a list? This is how you create and use one. That is enough for the beginner course, and the intermediary. Only when you're talking to backend library developers, or those unfortunate souls that have to dig through legacy code from people that kept applying what they learned first (how to code their own container classes with manual memory management and all), then you have to pull back the curtain and show the basement plumbing.

I've been working with C++ for two decades. The number of times I had to new / delete anything, I can count on one hand.

The most aggravating thing I know is instructors asking their students to re-implement standard functionality (like writing their own list class, or implementing bubblesort). It's wasted time; chances are you never will have to actually write anything like that in the field -- not if you did spend that time learning what is already there, and how to use it, instead on how to re-implement it.

Re: Advice for novice programmers thread

Posted: Thu Jul 15, 2021 4:49 am
by vvaltchev
nullplan wrote:
vvaltchev wrote:How could you create a linked list?
With interfaces.

Ah, OK, fair point. But let me remark that using placeholder nodes has a price as well:

- the creation/destruction for placeholder objects take extra take time
- the placeholder object will consume extra memory during its whole life time
- the isEmpty() check is mandatory as well as the null pointer check in the other case
- in case of misuse of the placeholder object (no checking) you'll get an exception, exactly as in the case of NULL
- placeholder objects require polymorphic objects (vtable), which is not a problem in Java because all objects are polymorphic anyways, but that's not the case in some languages.

Said that, I know that in some cases such stub objects make the implementation simpler. For example in the case of red-black trees. But, we have to be careful to use always the same instance for the placeholder object, otherwise, having a dedicated placeholder object for every child that doesn't exist will mean almost doubling the number of objects in the binary tree!
nullplan wrote:Excuse syntax errors in the above code, I haven't done this in a while. In any case, as you can see, not a single null reference is present or desired. Object oriented programming allows you to do things very differently from pure procedural programming. I do not think having all references be nullable is a good thing. In C++, references are never NULL. There is a separate type to denote the possibility for an object to not be filled (called Nullable, similar to Haskell's Maybe), and so you cannot pass a reference that may be NULL to a function that can't deal with it.
Well, C++ references are good and I use them all the time, but they cannot replace pointers, simply because they cannot change the object they refer to and also because they cannot be set to nullptr. Yes, in Haskell everything is different, but that's a purely functional programming language and pure (non-nullable) references are a regular thing. Sure, I agree that the concept of a nullable attribute is interesting and usable outside of Haskell. For example, in the latest version of Dart, I believe all Java-style pointers will be non-nullable by default and a @nullable attribute will be supported.
nullplan wrote:Using the type system to detect such errors is one of the hallmarks of higher level programming, so it is a bit of a shame to see people not take advantage of it. In C, I have started using small structs all over the place to keep several low-level things apart from each other. I have a struct for 4-byte little endian values, and 4-byte big endian values, and functions to translate between those and actual integers. I never have to deal with byte swapping ever again!
Well, I agree: if you can use the type system to your advantage for free, than there's no reason to not do it. I do have a similar example too. Tilck's linked list is inspired by Linux's intrusive linked list implementation but I don't like having using list_head for everything. That's why I have:

Code: Select all

struct list_node {
   struct list_node *next;
   struct list_node *prev;
};

struct list {
   struct list_node *first;
   struct list_node *last;
};
Which are identical from the data point of view, but semantically different. I would also use different types for LE32 and BE32, like you did in order to avoid mixing them.

Don't get the wrong idea that I'm a sort of low-level "hacker" who doesn't care about type systems and semantics. I do care, but I don't wanna make compromises with performance as well. So, I tend to use more what is cheap, most of the time. Obviously, it depends on the project I'm working on.

Re: Advice for novice programmers thread

Posted: Thu Jul 15, 2021 5:14 am
by vvaltchev
Solar wrote:It's not a war; it really isn't, not for me. This is relaxed chat, for me. If it isn't for you, sorry, and this is my last post on the matter as well.
I don't want discussion to turn in to war either but.. it's super easy to get heated when opinions diverge so much and we do the mistake of trying to convince the other person.
Solar wrote:This is something I have experience in, and if you and I had the time (I don't, though, sorry) I'd love to show you what I mean in practice. I completely understand your POV, I've been there not that long ago myself. I even started an online blog series to teach C++ "ground up", "oldschool", which was how I learned it myself after all.

Which was exactly when I realized how many problems you create that way.
OK, I appreciate the good intentions. I'd just say that almost everybody out there believes in what you're saying and all the conferences about C++ repeat the same point over and over again. So, I honestly believe that my approach is in the minority here.
Solar wrote:Not a defect, but a crutch, dating back to a time when pointers were all we had. You don't need pointers when you can have references -- which, incidentially, can never be NULL. References are simply superior to pointers in every conceivable way.
I disagree, but I believe that, in your world-view about software development that makes completely sense. Again, we don't disagree in details, we have a fundamentally different system of values. We're both right in our own system of values. Unfortunately for me, most people in the industry are closer to yours than mine.
Solar wrote:See? You think "linked list", and immediately think about its innards, about the "next pointer" in there. I think "linked list" and immediately know that that's a standard container I can just use.
Yep, I know that position. You don't want to teach people a deep understanding of software. You want them to just use pre-built blocks without thinking. Alright.
Solar wrote:Thinking about innards, thus breaking the abstraction, is exactly the kind of thinking that perpetuates problem of people approaching C++ bottom-up. It absolutely does not matter how a linked list works internally, because we have a complete implementation available.
If you don't know how it works internally, you won't be able to use it well. You'd use it mechanically, often in the wrong place or in the wrong way. When I was studying CS, I remember how many students before my eyes didn't pass the test because the professor noticed that they used Java's LinkedList's get(int index) method inside a for loop, leading to a quadratic complexity. They should have used ArrayList instead.
Solar wrote:The most aggravating thing I know is instructors asking their students to re-implement standard functionality (like writing their own list class, or implementing bubblesort). It's wasted time; chances are you never will have to actually write anything like that in the field -- not if you did spend that time learning what is already there, and how to use it, instead on how to re-implement it.
Well, how can we be further than this? You want people to use things without knowing how they work. That's a very efficient way to write bad software IMHO. I believe in the opposite: before using something, you need to have a decent understanding of how it works. The best way of having a good understanding of something is to re-implement it, for educational purposes.

EDIT: grammar and typo fixes.