oh god, i find the sidebar so intensely annoying. glad i have the Dom Delete addon, i would never manage to read anything otherwise
A Dom Delete addon? Is it faster than hitting f12, clicking on the offending element and hitting delete?
151–160 of 162 posts
oh god, i find the sidebar so intensely annoying. glad i have the Dom Delete addon, i would never manage to read anything otherwise
A Dom Delete addon? Is it faster than hitting f12, clicking on the offending element and hitting delete?
Earlier quoted context omitted.
> But then anyone could just instantiate an invalid Name without calling the parse_name function and pass it around wherever This is nothing new in C. This problem has always existed by virtue of all struct members being public. Generally, programmers know to search the header file / documentation for constructor functions, instead of doing raw struct instantiation. Don‘t underestimate how good documentation can driv…
Sometimes you want the struct to be defined in a header so it can be passed and returned by value rather than pointer. A technique I use is to leverage GCC's `poison` pragma to cause an error if attempting to access the struct's fields directly. I give the fields names that won't collide with anything, use macros to access them within the header and then `#undef` the macros at the end of the header. Example - an immu…
Hmm, I found a solution and it was easier than expected. GCC has `__attribute__((designated_init))` we can stick on the struct which prevents positional initializers and requires the field names to be used (assuming -Werror). Since those names are poisoned, we won't be able to initialize except through functions defined in our library. We can similarly use a macro and #undef it.
Full encapsulation of a struct defined in a header:
#ifndef FOO_STRING_H
#define FOO_STRING_H
#include
#include
#include
#if defined __has_include
# if __has_include("config.h")
# include "config.h"
# endif
#endif
typedef size_t string_length_t;
#ifdef CONFIG_STRING_LENGTH_MAX
#define STRING_LENGTH_MAX CONFIG_STRING_LENGTH_MAX
#else
#define STRING_LENGTH_MAX (1
Aside from horrible pointer aliasing tricks, the only way to create a `string_t` is via `string_alloc_from_chars` or other functions defined in the library which return `string_t`. #include
int main() {
string_t s = string_alloc_from_chars("Hello World!");
if (string_is_valid(s))
puts(string_to_chars(s));
string_free(s);
return 0;
}Earlier quoted context omitted.
> It's inelegant We obviously disagree with the coding organization we prefer, so I find that rather elegant, but this doesn't sound like a substantial discussion. You as the language author are obviously quite content with the choices D made. > This is inelegant because all other types do not need a prefix. I don't find that. It makes it rather possible to clearly distinguish between transparent and opaque types. Th…
Can you justify C rejecting the following code: int *p, *q; auto x = p * q; ?
Also what has this to do with the current discussion?
Earlier quoted context omitted.
As I see it, the problem with languages trying to replace C is that they not only try to fix fundamental flaws, but feel compelled to add unneeded features and break C's simplicity.
C is a simple language, but that simplicity leads to non-portable code and lots of klunky, ugly things like using the preprocessor as a substitute for conditional compilation, imports, lambdas, metaprogramming, etc. You don't have to use unneeded features that are in D. The core language is as simple as C, to the point where it is easy to translate C to D (in fact, the compiler will do it for you!).
"You don't have to use unneeded features" True, but that doesn't work in practice, for example the intentions to use only limited C++ features in new projects, that end up bogged down with the other features anyway because of "new toy to play with" effect. What isn't there can't be used and keeps the language lean and clean (and not mean ;-) ).
Earlier quoted context omitted.
Can you justify C rejecting the following code: int *p, *q; auto x = p * q; ?
Yes, because I also don't know what this is supposed to mean? The product of two addresses? Dereferencing one pointer, and then combining them without an operator? And what's the type going to be, "pointer squared"? Also what has this to do with the current discussion?
The point is C does not allow doing anything you want. The C type system, for example, places all kinds of restrictions on what code can be written. The underlying CPU does not have a type system - it will multiply two pointers just fine without complaint. The CPU does not even have a concept of a pointer. (The C preprocessor doesn't have a notion of types, either.)
The point of a type system is to make the code more readable and reduce user errors.
We have a difference of opinion on C. Mine is that C should have better rules to make code more readable and reduce user errors. Instead it remains stuck in a design from the 1970s, and has compromised semantics that result from the severe memory constraints of those days. You've defended a number of these shortcomings as being advantages.
Just for fun, I'll throw out another one. The C cast syntax is ambiguous:
(T)(3)
Is that a function call or a cast of 3 to type T? The only way to disambiguate is to keep a symbol table of typedef's so one can determine if T is a type or not a type. This adds significant complexity to the parser, and is completely unnecessary.The fix D has for this is:
cast(T)(3)
where `cast` is a keyword. This has another advantage in that casts are a blunt tool and are associated with hiding buggy code. Having `cast` be easily searchable makes for better code reviews.Earlier quoted context omitted.
C is a simple language, but that simplicity leads to non-portable code and lots of klunky, ugly things like using the preprocessor as a substitute for conditional compilation, imports, lambdas, metaprogramming, etc. You don't have to use unneeded features that are in D. The core language is as simple as C, to the point where it is easy to translate C to D (in fact, the compiler will do it for you!).
"lots of klunky, ugly things" I wonder how much of that is caused by too complex thinking. It seems that simplicity is very difficult for most people. "You don't have to use unneeded features" True, but that doesn't work in practice, for example the intentions to use only limited C++ features in new projects, that end up bogged down with the other features anyway because of "new toy to play with" effect. What isn't t…
We've introduced the notion of "editions" in D lately, and its purpose is to remove features that have not proved their value over time.
Earlier quoted context omitted.
Yes, using the same Gtk example, the way you’d forward declare GtkLabel without including gtklabel.h in your header would be: struct _GtkLabel; typedef struct _GtkLabel GtkLabel; // Use GtkLabel* in declarations
Why are you complicating things? Struct and Unions are different namespaces for a reason. typedef struct GtkLabel GtkLabel; works just fine.
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtklabel....
Earlier quoted context omitted.
Why are you complicating things? Struct and Unions are different namespaces for a reason. typedef struct GtkLabel GtkLabel; works just fine.
I’m simply stating how actual Gtk is written: https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtklabel....
Earlier quoted context omitted.
Yes, because I also don't know what this is supposed to mean? The product of two addresses? Dereferencing one pointer, and then combining them without an operator? And what's the type going to be, "pointer squared"? Also what has this to do with the current discussion?
> Also what has this to do with the current discussion? The point is C does not allow doing anything you want. The C type system, for example, places all kinds of restrictions on what code can be written. The underlying CPU does not have a type system - it will multiply two pointers just fine without complaint. The CPU does not even have a concept of a pointer. (The C preprocessor doesn't have a notion of types, eith…
I thought we were discussing specific issues, I did not claim, that C doesn't have things that could be different. For example the interaction of integer promotion and fixed size types is completely broken (as in you can't write correct portable code) in my opinion.
> The C type system, for example, places all kinds of restrictions on what code can be written. The underlying CPU does not have a type system - it will multiply two pointers just fine without complaint. The CPU does not even have a concept of a pointer.
As you wrote a pointer is not an address. The CPU lets you multiply addresses, but C also let's you multiply addresses just fine. The type for that is uintptr_t. Pointers are not addresses, e.g. ptr++ does not in general increment the address by one.
> The C preprocessor doesn't have a notion of types, either.
It doesn't even have a concept of symbols and identifiers, which makes it possible for you to construct these.
> You've defended a number of these shortcomings as being advantages.
Because I think they are. It's not necessarily the reason why they are there, but they can be repurposed for useful stuff and often are. Also resource constraints often result in a better product.
I still only declare variables at the begin of a new block, not because I wouldn't write C99+, I do, but because it makes the code easier to read when you can reason about the participating variables up front. I can still introduce a variable when I feel like, just by starting a new block. This enables me to also decide when the variables go out of scope again, so my variables only exist for the time, I really want them to, even if that is only for 3 lines.
> Just for fun, I'll throw out another one.
That's just a minor problem in compiler implementation, and doesn't result in problems for the user. Using the same symbol for pointer dereference and multiplication is also similar.
(a) *b
Is that a cast or a multiplication? These make for funny language quizzes, but are of rare practical relevance. Real world compilers don't completely split syntactic and semantic parsing anyway, so they can emit better diagnostics and keep parsing upon an error.> You've defended a number of these shortcomings as being advantages.
My initial comment was about a shortcoming, which doesn't actually exist.