Most people are entirely unaware of how much data Facebook is collecting about them. Raising awareness about that is a noble goal, but it's not mutually exclusive with stopping Facebook from exploiting their naivety.
But it's a temporary measure that only works against Facebook and maybe other companies that do it above the board. In other words, you're kicking the companies that are honest about it in the teeth. Meanwhile the really shady companies will continue doing it, because they are outside of the jurisdiction. This is like trying to provide security through obscurity. Yes, it works on a large scale, but it's not really security.
In other words, you're kicking the companies that are honest about it in the teeth.
Where exactly was Facebook's ever honest about what data they hover up?
Want just but two examples from dozens?
That cutesy rabbit and the super shady patterns used for permission to suck up all your communication on Android would be exhibit #1
I would add the fact that they abused the phone number provided for two factor authentication to spam you with adverts. A clear abuse of its intentions and a kick in the teeth of security in general.
There are dozen more examples. If in doubt search for "The apologies of Mark Zuckerberg" on DuckDuckGo.
I tried to love Zig but the lack of destructors are killing me! They're such a useful tool for resource management, and apparently they weren't added in order to make all control flow "explicit" or something.
I've never actually used Zig (yet), but I think their choice is reasonable. It's not an object oriented language. Using destructors for resource management in such languages is great, but I've also seen a lot of C++ code that abuses the object-lifetime machinery. The most common is lock pseudo-objects, which "exist" only so that they can be released via a destructor when they go out of scope. Those aren't real objects. They don't contain any data. They're abstractions, which should be dealt with with other guard/context language structures. I'll admit that "defer" is a bit low-level, but it does handle most resource-release use cases in a way that's consistent with the rest of Zig.
What non-object-oriented approach would you suggest instead?
> Using destructors for resource management in such languages is great, but I've also seen a lot of C++ code that abuses the object-lifetime machinery.
That's not abuse, that's the most important pattern in C++ (RAII). You mustn't think of C++ "objects" as Java or C# or Smalltalk objects - they are not, they are deterministic resource managers before everything.
> You mustn't think of C++ "objects" as Java or C# or Smalltalk objects
As long as people persist in calling them objects, and use all of the other object-oriented concepts/terminology such as classes and inheritance, people will expect them to be objects. That's not unreasonable. It's absurd to look down your nose at people who are taking you at your word.
These other uses are hacks. If you want to be able to attach something to a scope that's great, actually it's a wonderful idea, but just be honest about it. Make scopes a first-class concept, give things names that reflect their scope-oriented meaning and usage. Python's "with" is a step in the right direction; even though the implementation uses objects, they're objects that implement a specific interface (not just creation/destruction) and their usage is distinct. That separation allows scope-based semantics to evolve independently of object-lifetime semantics, which are already muddled by things like lambdas, futures, and coroutines. Tying them together might be an important pattern in C++, but it's also a mistake. Not the first, not the last. Making mistakes mandatory has always been the C++ way.
> If you want to be able to attach something to a scope that's great, actually it's a wonderful idea, but just be honest about it.
We don't want to attach resources to scopes, we want to attach them to object lifetimes. That's why defer/with/unwind-protect are not alternatives to RAII. The lifetime of an object I pushed to a vector is not attached to any lexical scope in the program text, it is attached to the dynamic extent during which the object is alive. While a scope guard always destroys its resource at the end of a block, RAII allows the resource lifetime to be shortened, by consuming it inside the block, or prolonged, by moving it somewhere with a dynamic extent that outlives the end of the block.
Here's an example where defer solves nothing: if I ask Zig to shrink an ArrayList of strings, it drops the strings on the ground and leaks the memory because Zig has no notion of the ArrayList owning its elements. You need to loop over the strings you are about to shrink over and call their destructors, which is literally the hard part, since the actual shrink method just assigns to the length field. The lack of destructors (Zig has no generic notion of a destructor) here impedes generic code since what you do for strings is different than what you do for ints.
RAII guards are real objects, they contain real data (drop flags), and they make code safer and more generic. If you don't like RAII, show comparable solutions (which scope guards are not), don't just call it a hack and adduce philosophical notions of how OOP should work.
> We don't want to attach resources to scopes, we want to attach them to object lifetimes.
Is that the royal "we"? Because for people who aren't you, it's only true some of the time. Sure, true resource acquisition/release is tied to object lifetimes. That's almost a tautology. But that doesn't work e.g. for lock pseudo-objects, which very much are expected and meant to be associated with a scope. It just happens to work out because the object and scope lifetimes are usually the same, but it's still a semantic muddle and it does break for things like lambdas and coroutines.
> if I ask Zig to shrink an ArrayList of strings
That's a silly and irrelevant example, having more to do with ownership rules (which C++ makes a very unique mess of) more than scopes vs. objects. Any Zig code anywhere that shrinks a list of strings had better handle freeing its (now non-) members. No, defer doesn't cover that case. Yes, destructors would, but this isn't an OO language. The obvious solution (same as in C) is to define a resize_string_list function. Again, what can you suggest in a non-OO language that's better?
> The lack of RAII here impedes generic code
You really don't want to get into a discussion about C++ and generics. Trust me on that. Yes, you need to do different things for strings and ints, but there are many ways besides C++'s unique interpretation of RAII (e.g. type introspection) to handle that.
> If you don't like RAII, show comparable solution
Done. Your turn. If you want to be constructive instead of just doctrinaire, tell us what you'd do without OO to address these situations better than existing solutions.
P.S. Also, what's with all the nonsense-word accounts in this thread taking offense at things said to jcelerier and responding with exactly the same points in exactly the same tone?
They are not comparable to RAII, see my comment above. Even the fact it has to bifurcate into defer and errdefer suggests that it lacks the generality to replace a totalizing resource management solution.
No, they're not the same as your beloved RAII, but this isn't an object-oriented language so it doesn't have destructors. For the third time, what better solution do you propose for a non-OO language?
This seems equivalent to scope(exit)/scope(success)/scope(failure) in D. The drawback of this construct is that you need to repeat 2 or 3 lines of code each time you need safe cleanup or a commit/abort type of construct. This can become pretty repetitive pretty fast.
One problem with module systems (in compiled languages) is, that they form dependency chains.
Imagine you change code in an upstream module. Now the compiler has to recompile all downstream modules. In C and C++ this only happens if you change the header file.
(On the other hand modern development techniques emphasize tests so you might only recompile your module and the testsuite until all tests pass and only then recompile all modules, minimizing the impact.)
For a full recompilation you can parallelize C and C++ compilations much better than any module system I know.
The C language is not designed for building huge programs by accretion of modules. The idea is that you build many independent programs, and then you glue them together using scripts.
> The idea is that you build many independent programs, and then you glue them together using scripts.
That doesn't exactly describe kernels or embedded systems, which are C's strongest bastions. Whether it's well designed for the purpose or not, whether modules are appropriate in that context or not, a significant majority of the C code out there (including most common web servers, databases, etc.) does not fit your description at all.
Building small programs and gluing together with scripts is great, but hardly relevant. You don't need includes or modules for that. What if you do need to build one large program, like those aforementioned web servers or databases, or (what I work on) a storage server? That's where the difference between textual inclusion and modules really comes into play, and modules are strictly better than includes in every way.
I think the problem here is that you're confusing modules with things built on top of modules - specifically package managers. A lot of the package managers out there are horrible and create more problems than they solve, but that has almost nothing to do with modules as a language construct.
>The C language is not designed for building huge programs by accretion of modules.
Can you give a single concrete example of a problem, because the above are all noops semantically speaking...
>The idea is that you build many independent programs, and then you glue them together using scripts.
This is a non-starter for most use cases outside pipeable shell commands (which are not the only kind of programs people want to write).
People need, and write, and have written for decades, large programs in C, and programs in C which have from 10s to 100s of headers files included (including recursively from included libs).
Like the etymology of a word doesn't necessarily convey its meaning, the "original intent" of something is often meaningless as to its actual practical use.
The idea you mention is valid, and is part of the Unix philosophy.
But it was never the idea that C should be used JUST for that.
In fact the first use of C was to write a whole operating system.
Well the systems I'm developing now consist off small interlocking C++ processes which use UNIX IPC to communicate across address spaces. It's not what most people are used to but it works very well in this case. The aren't shell commands like you're thinking of but they are discrete programs.
Oh, I don't know. Gluing the programs together using RPC and REST seems to be working so well for everyone else. Why do you even need a shell or unix style pipelines, right?
You use the MMU to create virtual address spaces and the kernel to provide a message passing interface. The MMU may cause you to incur some latency but in exchange you get some pretty good isolation between components of your system. Even more so if your kernel is proven using formal methods.
There's no need to get snarky. I've used similar parts before, for example TI's Hercules RM4 does not have an MMU either and so what I said wouldn't apply there. But that doesn't mean you would never have an MMU.
Indeed, my apologies. I actually quite like the idea. It reminds me a lot of Erlang, where you set up a bunch of small processes and if any of them die, you can a) try to recover quickly, or b) run in reduced functionality mode. I just haven't been fortunate enough to work with embedded processors where it'd be a good fit; they've either been on the small side (Cortex M, MSP430, AVR) or on the big side (iMX6, AM335x) and just run full-blown Linux.
1. "Single return and out parameters" should have a special mention for Haskell, since Haskell doesn't even have multiple input parameters!
2. Python has assignment expressions now.
Overall, it's a pretty good list of shortcomings of C, but I disagree with several of the points: (a) special-casing subtraction lexing to be whitespace sensitive is silly, and (b) integer division is essential whenever working with arrays or modular arithmetic, and converting types explicitly, like Rust mandates, is definitely the way to go. Who knows if I'd want a float, double, rational or currency type to be the output, anyway?
Numbers are hard. They can be made to look easy, but that just sweeps the corner cases under the rug.
Probably what people want is a Number type providing integer bignums for those situations when you don't want to care, a set of "machine integer" types with controllable overflow handling, IEEE floating point, a Rational/Fraction so you can handle 1/3 correctly, a Money type with controllable rounding, and COBOL-style "picture" types.
Oh, and complex numbers, and matrix types of all of the above.
JavaScript is a god language. Changing Array.prototype is very much considered an antipattern, except in the case of shims, where it's really useful. JavaScript is reinventing itself, introducing a nice, traditional OOP facade with `class`, and making improvements to functional-ish programming with `let` (as opposed to `var`), arrow functions, and object and array destructuring. The DOM is still very much a "try to display something at all costs" mess that doesn't at all fail fast, but most of the things that you want to happen are indeed happening!
Huh? Binaries downloaded off the Internet work just as fine on Linux as they do on Windows! Package managers just give you very convenient updating and a chain of trust to greatly reduce the risk of installing malware; and these are things people definitely want - see the App Store, the Play Store, Homebrew, Chocolatey, etc.
> Binaries downloaded off the Internet work just as fine on Linux as they do on Windows!
If that is true, then why do developers keep telling Linux people that distribution to Linux Desktop is a problem? What issue do AppImage and Snap and FlatPak exist to try and solve?
> and these are things people definitely want - see the App Store, the Play Store, Homebrew, Chocolatey, etc.
Chocolatey has a paltry install base, Homebrew is only used by developers, and you don't really get a choice about the mobile stores.
Linux is a headache for two reasons: (1) because it's basically packaging your app for half a dozen different app stores, so you need tools that make that easier for you, and (2) lots of frameworks have no, buggy or unwieldy Linux support, because Linux had such a small userbase. So you're right, it is more of a headache for the developer, but the end user has a much nicer experience (it can't be overstated how nice it is to be able to install almost anything with one command, and update everything with another). Of course, binaries can be downloaded off the Internet just like on Windows, and some apps, like Chrome, will even keep themselves up-to-date without a package manager, again like on Windows, but each app having its own messy, non-standardized updating scheme is something of an antipattern on Linux, even if it's par for the course on Windows.
> it is more of a headache for the developer, but the end user has a much nicer experience (it can't be overstated how nice it is to be able to install almost anything with one command, and update everything with another)
It's a trade off. For that you're giving up control as a user about what can and cannot be installed on your system, you're giving up portable applications, being able to have applications on different media, having different versions of the same applications, etc.
I'm an end user too, and I don't want to make that trade off. I imagine there are many others who agree.
I still don't understand - you can still have a standalone executable if you want, nothing's stopping you! Package managers just streamline the common case of "I just want to install some software on this computer and have it update automatically". Linux has all the freedom of Windows and more.
You pay for Windows, but Linux is free. Windows is filled with ads; Linux has none. Windows is slow; Linux is less slow. Windows tried to pull some weird tablet hybrid nonsense; Linux desktops are just desktops. Cinnamon, Mate and KDE took the very best parts of old Windows and made them better. Gnome and Pantheon ripped off macOS and they're also great. Every single one of them is more polished and more useable than Windows 10.
But seriously, who in their right mind would tolerate advertisements in software that they paid good money for?
I have never seen an ad in windows in my entire life on any of my machines. Apparently it is the first thing I disable when I open up the settings on a new install. It's gotten to the point that I'm almost curious about it. Ubuntu has the amazon integration which bothers me about just as much.
Ubuntu tried to pull some weird netbook phone hybrid that didn't work well on any type of device. 8 years we had to live with Unity.
I'd say that the UI of Windows 10 is about ten years ahead of anything in the linux world (and I doubt linux well ever be as polished). I say that as someone who is possibly going to do the switch to linux this year, but I'm in for a rough transition.
Some one who has deals with top 5 orgs on Earth gives zero shits about the software or who made it, as long as it gets the job done. Actually, they might care, in a sort of "Yes, Virginia, there is a Santa Claus" sort of way, but if you're on deadline and there are jobs on the line, people paying rent, you really can't afford to worry about whether Office costs you $100/year every year for the rest of your life.
Yes, for anyine who wants to do further research it's called Proton. Valve has tried several times in the past to make gaming on Linux more attractive, but this has by far been their most successful attempt.
A lot of games don't even start on my Antergos setup. I refuse to run ubuntu, because I don't like it (mostly package naming, and a lot of the time I feel like it's poorly configured at least when I was starting out). I personally have had a negative experience whenever I use a Debian derivative.
OCaml is a very fun language in my experience. Apparently they were going to add ad-hoc polymorphism in the form of modular implicits, but I have no idea what happened to that.