[HN Gopher] Pretty.c
       ___________________________________________________________________
        
       Pretty.c
        
       Author : synergy20
       Score  : 322 points
       Date   : 2024-10-24 03:01 UTC (19 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | mydriasis wrote:
       | Wow, neat! The wildest part to me is
       | 
       | > And it's backwards-compatible with C and all of its libraries!
       | 
       | I can't wait to give it a shot! This looks like a riot.
        
         | geon wrote:
         | Have you heard of Zig?
        
           | oguz-ismail wrote:
           | It requires a different compiler. This is just a collection
           | of C preprocessor macros
        
             | ptspts wrote:
             | The Zig toolchain can compile both Zig and C.
        
               | klardotsh wrote:
               | Yes, but the Zig toolchain is not
               | $YOUR_EXISTING_C_COMPILER_YOU_ALREADY_KNOW_AND_USE
        
       | textread wrote:
       | Is it possible to tangle the Readme into pretty.h? In other
       | words, are the codeblocks in the orgfile exhaustive.
       | 
       | I love the literate way you have explained your thought process
       | in the readme.
        
         | aartaka wrote:
         | Yes, code blocks in Org are executable, but I was aiming for
         | simple embedding and zero build-time, thus conservative choice
         | of separating README and the actual header.
        
       | OsrsNeedsf2P wrote:
       | This is terrifying
        
         | aartaka wrote:
         | Thanks!
        
       | yjftsjthsd-h wrote:
       | I have not decided how I feel in general, but:
       | 
       | > Everyone defines these, so why not provide them?
       | 
       | Honestly, that's fair.
        
       | dymk wrote:
       | > turn any codebase into a beginner friendly one
       | 
       | Okay then.
       | 
       | I was hoping to see a "this is just for fun" disclaimer but
       | didn't see one. Please never actually use this in a project that
       | other people will have to read or contribute to.
        
         | ipsum2 wrote:
         | > Provide so much syntactic sugar as to cause any C developer a
         | diabetes-induced heart attack.
         | 
         | seems like its obvious to me that its a joke
        
           | rebolek wrote:
           | It's a joke that I would happily use.
        
             | AnthonBerg wrote:
             | C is funny, in many ways.
        
             | aartaka wrote:
             | You're welcome!
        
         | thiht wrote:
         | Not everything needs to be stated explicitly, where's the fun
         | in that?
        
         | TheRealPomax wrote:
         | No promises, people who want to have fun are going to have fun
         | despite requests not to have fun.
        
       | ipsum2 wrote:
       | `equal(0.3, 0.2 + 0.1); // true`
       | 
       | how is this wizardry possible?
        
         | defrost wrote:
         | Is _What Every Computer Scientist Should Know About Floating-
         | Point Arithmetic_ wrong ??!!
         | 
         | addendum: _why are obviously rhetorical questions are taken so
         | literally here?_
        
           | leansensei wrote:
           | Because text doesn't convey sarcastic voice tonality, so the
           | intent is far from obvious.
        
             | defrost wrote:
             | Sarcastic? Okay, if you say so.
             | 
             | Picking out an obvious define function that compares a
             | float with a float sum of that nature should indicate an
             | good understanding of _why_ that might be called wizardry
             | and deserving of a second look.
             | 
             | Hats off to the peer comment that suggested scaling against
             | epsilon rather than simpliy regurging the substitution "as
             | was" from the header.
             | 
             | The scaling is better in general, optional in some specific
             | contexts.
        
           | ipsum2 wrote:
           | It's meant as both humorous and a nerd snipe :)
        
         | slimsag wrote:
         | it uses absolute difference epsilon equality ('close enough to
         | be considered equal'):                   static int
         | pretty_float_equal (float a, float b) { return fabsf(a - b) <
         | FLT_EPSILON; }         static int pretty_double_equal (double
         | a, double b) { return fabs(a - b) < DBL_EPSILON; }
         | static int pretty_long_double_equal (long double a, long double
         | b) { return fabsl(a - b) < LDBL_EPSILON; }
        
           | vbezhenar wrote:
           | This is wrong code. It only works somewhat correctly when a
           | and b around 1.
        
             | stabbles wrote:
             | Yeah, should be scaled like |x - y| <= e * max(|x|, |y|)
        
               | aartaka wrote:
               | Will do.
        
               | jffhn wrote:
               | If both terms are infinites and of same sign, subtraction
               | will give NaN and it will fail.
        
               | listeria wrote:
               | How is that a problem? infinities shouldn't be considered
               | equal
        
               | jffhn wrote:
               | For IEEE 754, and in Java for example, they are. Only NaN
               | is not equal to itself (and different from itself).
        
         | wjbr wrote:
         | static int pretty_float_equal (float a, float b) { return
         | fabsf(a - b) < FLT_EPSILON; }
        
         | masklinn wrote:
         | It uses type dispatch to perform an epsilon comparison:
         | static int pretty_float_equal (float a, float b) { return
         | fabsf(a - b) < FLT_EPSILON; }
         | 
         | So it's https://docs.python.org/library/math.html#math.isclose
        
           | hmry wrote:
           | This code is incorrect, but I don't blame them. :) Probably
           | one of the most common float-related mistakes, even among
           | people who "know how floats work".
           | 
           | FLT_EPSILON is the difference between 1.0 and the next larger
           | float. It's impossible for numbers less than -2.0 or greater
           | than 2.0 to have a difference of FLT_EPSILON, they're spaced
           | too far apart.
           | 
           | You really want the acceptable error margin to be relative to
           | the size of the two numbers you're comparing.
           | 
           | Also, everyone should read the paper "What, if anything, is
           | epsilon?" by Tom7
        
             | im3w1l wrote:
             | I would go even further and say that any equality
             | comparison of float numbers has to be a one-off special
             | case. You need to know how much error can arise in your
             | calculations, and you need to know how far apart
             | legitimately different numbers will for your particular
             | data. And of course the former has to be smaller than the
             | latter.
        
             | aartaka wrote:
             | Indeed, FLT_EPSILON is not a one-size-fits-all solution,
             | but it's good enough for frequent case of comparing big
             | enough numbers, which is not covered by regular ==. So it's
             | a convenience/correctness trade-off I'm ready to make.
        
               | hmry wrote:
               | If the numbers you are comparing are greater than 2,
               | abs(a - b) < FLT_EPSILON is equivalent to a == b. Because
               | it's not possible for two large numbers to not be equal,
               | but also closer together than FLT_EPSILON.
        
               | jdthedisciple wrote:
               | what                   // FLT_EPSILON == 0.01
               | equal(4.999, 5); // true         4.999 == 5;      //
               | false
               | 
               | am i missing?
        
               | hmry wrote:
               | FLT_EPSILON is not 0.01, it's 0.00000011920929.
               | 
               | But it's impossible to have a number that's
               | 0.00000011920929 less than 5.0, or 0.00000011920929 more
               | than 5.0, because the floats with enough magnitude to
               | represent 5 are spaced further apart than that. Only
               | numbers with magnitude < 2 are spaced close enough
               | together.
               | 
               | In other words, the only 32-bit float that's within
               | +-0.00000011920929 of 5.0 is 5.0 itself.
        
               | jdthedisciple wrote:
               | Oh you're right, thanks for the explanation!
               | 
               | Gotta research now where the 0.00000011920929 number
               | comes from...
        
               | masklinn wrote:
               | It's the distance between 1.0 and the next representable
               | float.
        
               | jdthedisciple wrote:
               | I got that but I am curious how to derive that number.
               | 
               | Is it representable as a non-trivial ratio of integers?
        
               | hmry wrote:
               | Good question! It's 1/(2**23), because 32 bit floats have
               | 23 bits after the decimal point
        
       | looopTools wrote:
       | I cannot wait to show this to a colleague of mine. He will kill
       | me XD
        
         | aartaka wrote:
         | Can't wait to learn of how it went!
        
       | bitwize wrote:
       | I'm reminded of the guy who did                   #define BEGIN {
       | #define END }
       | 
       | and a whole bunch of other macro-larkey just to make C look more
       | like Pascal. Only then would he deign to code in it.
        
         | epcoa wrote:
         | https://en.wikipedia.org/wiki/Stephen_R._Bourne
         | 
         | https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh
        
           | sph wrote:
           | Now that's just silly. And I see the backwards keyword
           | terminators (LOOP/POOL).
           | 
           | I have wondered why we have case/esac, if/fi but while/done.
           | I imagine the author himself figured that while/elihw would
           | just be entirely ridiculous.
        
             | pavlov wrote:
             | Just call it wyl/lyw. Pronunciation maintained, problem
             | solved.
        
             | giucal wrote:
             | > I have wondered why we have case/esac, if/fi but
             | while/done.
             | 
             | With the reverse-keyword convention we'd get "od", not
             | "elihw", though.                   while ...    for ...
             | do           do             ...          ...         od
             | od
             | 
             | The 'od' utility already existed, apparently, so Bourne
             | opted for "done".
             | 
             | [edit: typos]
        
       | azinman2 wrote:
       | > Deprecate Lua, Python, JavaScript, Ruby and a dozen other
       | languages, because Pretty C is the ultimate scripting language,
       | but lightning-fast and strongly typed!
       | 
       | Umm... that's quite the goal.
       | 
       | I'll stick with deprecated Python.
        
         | fancyfredbot wrote:
         | Deprecate Python?! You'll have to deprecate me first! ;-)
        
           | psychoslave wrote:
           | We will all reach this status at some point, though the silly
           | code we produced might stick a bit longer in some legacy
           | codebase. :D
        
       | Uptrenda wrote:
       | Type names are nice; Perfect choice for the in-built func macros
       | (like min); Len -- love it. Named boolean operators -- might be a
       | bit much but go for it; Ternaries are illegible so you can only
       | improve them; Not completely sold on all your loop definitions
       | but some make sense to me; Resource tracking is impressive; The
       | for... look a bit ugly -- could probably call it something else.
       | 
       | All in all: quite a solid attempt. I'll give you 8/10 for the
       | design of this. The way you sketched this out in C using macros
       | is really elegant. This actually looks like good code. Would I
       | use it? It's a new language and I like C already. It could help
       | people learn C and think about language design. Since the way
       | you've done this is very clear.
        
         | aartaka wrote:
         | Well, you don't have to use it all. My projects mostly use
         | booleans, len(), max/min, and some operator aliases, because
         | there wasn't much need for other tasty stuff yet. So give it a
         | shot, even if for a couple of operator macros!
        
           | Uptrenda wrote:
           | You know I expected your macro file to be unreadable moon
           | math. But it actually doesn't look bad.
        
       | Validark wrote:
       | Evil, yet beautiful. Hats off to you.
        
         | aartaka wrote:
         | Thanks!
        
       | lpapez wrote:
       | All that is missing is a garbage collector. Should be possible to
       | implement one by overriding malloc & friends?
        
         | vidarh wrote:
         | You can use the Boehm-Demers-Weiser GC with C. It's
         | conservative, because it has to be with C, so it may/will miss
         | things (it will treat integers etc. as potential pointers, and
         | so avoid freeing anything "pointed to" by them), and so it
         | works best as an extra layer of protection/leak detector, but
         | it can be used as a replacement for freeing memory too.
        
       | gpuhacker wrote:
       | Reminds me of a C++ codebase I once had to inspect that was
       | entirely written as if it were written in Java. With camelcase
       | naming for everything, getters and setters for every class
       | variable, interfaces everywhere.
        
         | bpye wrote:
         | Good job they weren't using MSVC I guess...
         | 
         | https://learn.microsoft.com/en-us/cpp/cpp/property-cpp?view=...
        
         | jart wrote:
         | You ain't seen nothin. Check out the bourne shell source code
         | from unix seventh edition. https://minnie.tuhs.org/cgi-
         | bin/utree.pl?file=V7/usr/src/cmd... I can't believe it's not
         | ALGOL.
        
           | teruakohatu wrote:
           | Wow, I was not expecting that! Was this style of C common
           | back then?
           | 
           | Before he wrote the Bourne shell the author wrote an ALGOL
           | compiler, and ALGOL inspired Bourne syntax:
           | 
           | https://en.wikipedia.org/wiki/ALGOL_68C
        
             | pasc1878 wrote:
             | There were article suggesting #define BEGIN { and #define
             | end }; to make C look more like Pascal.
             | 
             | I think in Europe C was not as common as other languages at
             | the time so the terseness looked odd.
        
               | pavlov wrote:
               | Also because the special characters were (and are)
               | difficult to type on European keyboards.
               | 
               | Characters like []{}\|~ are behind multi-finger access
               | and often not printed at all on the physical keys (at
               | least in the past). You can see how this adds a hurdle to
               | writing C...
               | 
               | Pascal was designed by a European, so he preferred
               | keywords which could be typed on every international
               | keyboard. C basically just used every symbol from 7-bit
               | ASCII that happened to be on the keyboards in Bell Labs.
        
               | smatija wrote:
               | Just as example, on my slovenian QWERTZ layout: [ -
               | altgr+f, ] - altgr+g, { - altgr+b, } - altgr+n, \ -
               | altgr+q, | - altgr+w, ~ - altgr+1.
               | 
               | You get used to them, though you start feeling like a
               | pianist after a short coding session. The one most
               | annoying for me are the fancy javascript/typescript
               | quotes, which I have to use all too often: ` - altgr+7.
        
               | ulbu wrote:
               | Today I learned that there exist people who use non-US
               | layouts when coding. That's spectacular!
        
               | pavlov wrote:
               | How did you think people outside the US learn
               | programming?
        
               | anthk wrote:
               | setxkbmap us -option ctrl:swapcaps -option compose:rwin
               | 
               | Problem solved. US layout, and with the right Window keys
               | you can compose European characters.
        
               | pavlov wrote:
               | There's so many assumptions here about a person who's
               | starting to learn programming.
               | 
               | For starters, that they're on Linux, they feel
               | comfortable running complex CLI commands, they can
               | memorize the U.S. layout just like that, and that they
               | can type without looking at the physical keys (because
               | changing the virtual mapping means keys produce something
               | else than what the label says).
               | 
               | In reality, the learner's first exposure to C family
               | languages is more likely to be a website where you can
               | run some JavaScript in a text box. And the first hurdle
               | is to figure out how to even type {}. American developers
               | just completely forget about that.
        
               | anthk wrote:
               | On the long term, using the native keyboard hinders
               | yourself a lot. I tried to do so with the Spanish (es)
               | layout, it's pretty much unergonomical.
               | 
               | It's looks like being deliberately designed for
               | press/office usage and not for proper programming.
        
               | SSLy wrote:
               | or maybe popular proglangs were designed for writing on
               | USAn press/office keyboards - remember that UNIX came to
               | be as a typesetting appliance -- disregarding anyone
               | else.
        
               | pavlov wrote:
               | I've been writing C and its progeny (C++, JavaScript,
               | Rust etc.) since 1990 on a Finnish keyboard.
               | 
               | The AltGr brackets are fine. The truly annoying character
               | to type is the backtick (which is a quite new addition to
               | the pantheon of special characters, C doesn't use it).
               | 
               | My personal opinion is that Niklaus Wirth had the better
               | overall ideas about clarity and inclusiveness in
               | programming language design, but that battle is long
               | lost. (What you consider the character set needed for
               | "proper programming" is really a relatively new
               | development, mid-1990s and later.)
        
               | schoen wrote:
               | Backticks were fairly important for shell scripting in
               | the past, but have officially been replaced with $(),
               | which can be nested.
               | 
               | My intuition is that Perl would be the most challenging
               | on a keyboard where it's harder to type unusual
               | punctuation, since it feels like a very punctuation-heavy
               | language, but I don't know whether it actually uses more
               | than C (I think the backtick has a shell-style meaning in
               | Perl too).
        
               | psychoslave wrote:
               | >it's pretty much unergonomical.
               | 
               | Well unless opting for something like Dvorak, you are
               | indeed doomed to something that was specificcaly designed
               | to please typewriter mechanical constraints without much
               | care for the resulting ergonomics.
               | 
               | I use a Bepo layout personally, on a Typematrix 2030 most
               | of the time, as French is my native language.
        
               | smatija wrote:
               | I tried switching to US a few times, but every time
               | muscle memory made me give up soonish - especially since
               | there are big benefits to using same keyboard layout as
               | other people in your office are using.
               | 
               | Also practically everytime I need to write a comment,
               | commit message or email I need my c, s and z. It's kinda
               | nice to have them only a single keypress away.
        
               | oezi wrote:
               | My hack: use caps key to switch to local keyboard layout
               | while holding it.
        
               | dagw wrote:
               | Love it! I use ctrl+space to switch, but your idea sounds
               | even better
        
               | cryptonector wrote:
               | Spectacular?? Terrifying. If I need to type non-ASCII
               | Latin characters I'll just use compose sequences. The
               | thought of a non-U.S. keyboard layout with modifiers
               | required to type []{}<> and so on is terrifying.
        
               | fuzztester wrote:
               | IIRC, Pascal had/has (* and *) as an alternative to { and
               | } , from the start, or from early on - as syntax for
               | start comment and end comment.
        
           | froh wrote:
           | https://minnie.tuhs.org/cgi-
           | bin/utree.pl?file=V7/usr/src/cmd...
           | 
           | wow.
           | 
           | thanks for this gem.
        
         | worstspotgain wrote:
         | > camelcase naming for everything, getters and setters for
         | every class variable, interfaces everywhere
         | 
         | This is not far off from the guidelines in many cases, e.g.
         | Windows code (well, not _every_ variable of course.) A lot of
         | Java design was copied from C++.
        
         | pasc1878 wrote:
         | I had that as well but also Java passes strings in as f(String
         | *) so the C++ code was f(new String("Hello")
        
         | rauli_ wrote:
         | I've seen similar codebases as well written by people who have
         | spent way too much time with Java. One even had it's own String
         | class which was just a wrapper for std::string with Java-like
         | methods.
        
         | shortrounddev2 wrote:
         | I think that's just OOP
        
           | aartaka wrote:
           | You might like https://aartaka.me/oop-c
        
       | leetsbehonest wrote:
       | That is pretty cool
        
       | unwind wrote:
       | Meta: the naming is ... strange.
       | 
       | The actual name of the repo is "pretty.c", but the name used for
       | the language/dialect/result/horrorshow[*] is "Pretty C".
       | 
       | The actual code file you include is called "pretty.h", which
       | makes sense since it's a header, of course. Confusing!
       | 
       | Edit: escapes.
       | 
       | [*] Yes, I'm a C programmer, currently hunting for black-marked
       | insulin to combat the rapid-onset diabetic attack from all that
       | sugar. Sorta.
        
         | nneonneo wrote:
         | I mean, don't say the repo didn't warn you!
         | 
         | > The goals for Pretty C are: Provide so much syntactic sugar
         | as to cause any C developer a diabetes-induced heart attack.
        
       | tromp wrote:
       | > ifnt for if(!...).
       | 
       | "unless" seems more readable than "ifnt".
        
         | tux3 wrote:
         | Another bikeshed is the infinite for(;;) loop being called
         | "always"
         | 
         | I've seen "loop" in other languages. But Qt calls it "forever",
         | and that is indeed very pretty. Very Qt, even
        
           | teruakohatu wrote:
           | > I've seen "loop" in other languages. But Qt calls it
           | "forever", and that is indeed very pretty. Very Qt, even
           | 
           | You can break a "forever" loop so I think "loop" is a better
           | name.
        
             | wwalexander wrote:
             | I don't know why "repeat" isn't very common in place of
             | while/loop/etc; it works out nicely grammatically.
             | repeat {}         repeat while <condition> {}
             | repeat {} while <condition>         repeat <count> {}
        
               | af78 wrote:
               | One possible reason:
               | 
               | > The word "REPEAT" should not be used in place of "SAY
               | AGAIN", especially in the vicinity of naval or other
               | firing ranges, as "REPEAT" is an artillery proword
               | defined in ACP 125 U.S. Supp-2(A) with the wholly
               | different meaning of "request for the same volume of fire
               | to be fired again with or without corrections or changes"
               | (e.g., at the same coordinates as the previous round).
               | 
               | https://en.wikipedia.org/wiki/Procedure_word#Say_again
               | 
               | More seriously, PASCAL has repeat-until loops, similar to
               | do-while loops in C.
        
               | aartaka wrote:
               | Pretty C does aliases "repeat" for "do", so yeah, I've
               | got you covered!
        
             | krylon wrote:
             | "indefinitely" might be a better name. (But I think loop is
             | indeed a better name.)
        
               | aartaka wrote:
               | Added in commit ef510ca!
        
               | layer8 wrote:
               | I hope you also add a "definitely", for symmetry.
        
             | aartaka wrote:
             | "loop" added in commit 626408b, thank you!
        
           | poincaredisk wrote:
           | #define ever ;;         for(ever) {}
        
             | codetrotter wrote:
             | #define never ;0;         for(never) {}
        
               | metalliqaz wrote:
               | for(evernt) {}
        
           | aartaka wrote:
           | "forever" added in commit 67ff9ef, thank you!
        
         | aartaka wrote:
         | Indeed! But I've reserved "unless" for a ternary conditional,
         | which is more useful anyway.
         | 
         | Oh shit wait, you're John Tromp, BLC creator! I'm a fan!
        
         | cdcarter wrote:
         | On the other hand, ifnt is fun to say outloud.
        
       | MrLeap wrote:
       | love. It.
        
         | aartaka wrote:
         | Thanks!
        
       | varjag wrote:
       | This made me immediately think whether MIT Loop of Common Lisp
       | was an inspiration here. Checked the user's profile and sure
       | enough, a lisper!
        
         | aartaka wrote:
         | Yes, LOOP is a huge inspiration and my favorite programming
         | language!
        
       | DeathArrow wrote:
       | This should have been invented 50 years ago!
        
         | aartaka wrote:
         | Yes, and it's a shame that underlying features were only
         | shipped in C11 (generics) and C23 (auto type inference!)
        
       | SuperHeavy256 wrote:
       | So sweet :))
        
         | aartaka wrote:
         | Yeah, I love sugar ;)
        
       | nneonneo wrote:
       | It claims to be a scripting language but you still have to
       | compile the programs. Boo! Add CINT
       | (https://root.cern.ch/root/html534/guides/users-guide/CINT.ht...)
       | and you can have instantaneous execution and even a REPL!
        
         | shakna wrote:
         | I'd prefer just using tcc [0]. Far lighter weight than that
         | monster. And C, not C++.
         | 
         | [0] https://bellard.org/tcc/tcc-doc.html
        
         | maccard wrote:
         | Given the idea behind this repo is to cause pain, why not add a
         | shebang to your file [0] to make it executable.
         | 
         | I saw a blog post a long time ago that went into the details of
         | how ./foo worked, and how it executed an elf file. You could
         | register `.c` programs in the same way to be compiled and run?
         | 
         | [0]
         | https://gist.github.com/jdarpinian/1952a58b823222627cc1a8b83...
        
           | nneonneo wrote:
           | Now I have a very evil idea: what about registering a binfmt
           | handler for the header bytes "#include"? Sure, it doesn't
           | handle _all_ C /C++ programs (notably any program that dares
           | to start with a comment), but it would not require modifying
           | any source code!
           | 
           | (For even more insanity I guess you could also trigger on //
           | and /*, although there's some risk of false positives then!)
        
         | aartaka wrote:
         | Well, who said that scripting language cannot be compiled? And
         | yeah, Clang-REPL is another way to make it REPL-friendly.
        
           | knome wrote:
           | generally they aren't, as scripting usually implies an
           | interpreter, though no one is stopping you from using a
           | wrapping script that quietly compiles on first run and caches
           | a bunch of executables somewhere. not much different than
           | python producing bytecode files as it goes along.
        
             | randomdata wrote:
             | Script usually implies some kind of task that runs once and
             | the exits. As opposed to a system that is expected to run
             | indefinitely.
             | 
             | There are good reasons for why scripts are often
             | interpreted and why systems are often compiled, but that's
             | not what defines them. There are definitely scripts that
             | are compiled and systems that are interpreted out in the
             | wild.
        
               | knome wrote:
               | 'scripting' is an ill-defined term with many
               | interpretations, certainly.
        
           | bityard wrote:
           | Sure, there is no "rule" against it. But words/phrases have
           | commonly-accepted meanings and willfully ignoring or
           | appropriating those meanings implies either cultural
           | ignorance or a concealed agenda.
           | 
           | If you want to insist that scripting languages can be either
           | compiled or interpreted, then its better to just drop it
           | altogether and just say "language" because the "scripting"
           | part has utterly lost its identity at that point.
        
         | suzumer wrote:
         | Cern uses cling now (https://github.com/root-project/cling)
        
       | ngcc_hk wrote:
       | Can we just pascal?
        
         | aartaka wrote:
         | I won't stop you, so be my guest.
        
       | swiftcoder wrote:
       | This is as horrific as it is wonderful.
        
         | aartaka wrote:
         | Thanks!
        
       | nicman23 wrote:
       | as someone that just started C, it looks pretty :)
        
         | aartaka wrote:
         | Thanks!
        
       | codeflo wrote:
       | Can someone clarify whether this is intended as a joke or whether
       | the author is actually confused? I mean, nothing about this makes
       | sense: it's not "scripting"; it claims to introduce "strong
       | typing" while it does nothing about typing; it introduces all
       | kinds of operator aliases "modeled after Lua and Lisp" that are
       | present in neither of these languages. But it's not an obvious
       | parody either, so I'm genuinely not sure.
        
         | AnthonBerg wrote:
         | I do not at all think the author is confused. Being confused is
         | OK though.
        
         | sandos wrote:
         | I mean he has to be serious, right: "Deprecate Lua, Python,
         | JavaScript, Ruby and a dozen other languages, because Pretty C
         | is the ultimate scripting language, but lightning-fast and
         | strongly typed!!"
        
           | aartaka wrote:
           | Author here. I don't see any problem with this
        
             | byroot wrote:
             | Well, as a starter C is rarely considered as "strongly
             | typed". Statically typed yes, but strongly typed not so
             | much.
        
               | aartaka wrote:
               | With C23 (nullptr, auto typing, typeof) and C11
               | (generics) it got more guarantees and type-related
               | primitives. You can still do void*, but you are strongly
               | discouraged from it.
        
               | byroot wrote:
               | #include "pretty.h"              void print_int(int
               | value){             println(value);         }
               | int main (int argc, string argv[])         {
               | long value = 23849234723748234;
               | print_int(value);         }
               | 
               | How is this strongly typed?                   $ cc test.c
               | -o test && ./test         -1411401334
               | 
               | And to be clear, weak vs strong isn't a boolean property
               | but a spectrum, but would be hard to argue with a
               | straight face than C is a strongly typed language.
        
               | brabel wrote:
               | C is likely the only example of a programming language
               | that is clearly statically typed while at the same time
               | being weakly typed. For a reason: as your example shows,
               | it's a really bad idea (but understandable for a language
               | from the 60's).
        
               | layer8 wrote:
               | C is from the 1970s.
               | 
               | Java is weakly typed in its generics, despite being
               | statically typed. I'm sure there are more examples.
        
           | thiht wrote:
           | That's pretty clearly said jokingly
        
       | throwaway19972 wrote:
       | Does "strong typing" now just mean "static typing"? Afaik both
       | lua and python are already strongly typed. Javascript is not and
       | I have no clue about ruby.
        
         | lelanthran wrote:
         | > Does "strong typing" now just mean "static typing"?
         | 
         | The distinction strong and weak typing is irrelevant in
         | practice.
         | 
         | Weak (but present) static typing beats strong dynamic typing
         | every single time, because what is valuable is _NOT_ _" Do I
         | see a type mismatch error only when a user accesses it?"_, it's
         | _" does this mismatch prevent a deployment?"_
         | 
         | IOW, the only distinction in production is dynamic typing vs
         | static typing, not strong typing vs weak typing.
        
           | throwaway19972 wrote:
           | > because what is valuable is NOT "Do I see a type mismatch
           | error only when a user accesses it?", it's "does this
           | mismatch prevent a deployment?"
           | 
           | I argue that understanding the semantics clearly and
           | unambiguously is the most relevant thing, and strong typing
           | tends to do that better (imho--with my only other examples
           | being javascript and the "stringly-typed" perl and some
           | random irrelevant BASIC dialects).
           | 
           | > Weak (but present) static typing beats strong dynamic
           | typing every single time,
           | 
           | Can you give me an example? I don't think I've ever heard of
           | such a thing. The closest I can think to this is maybe,
           | arguably, the use of `void*` pointers in C which is difficult
           | to see as anything other than pragmatism rather than some
           | deeply beneficial way to write code--even explicit casts
           | produce much more readable code. Another argument I could see
           | is for operator overloading, which (IMO) produces much less
           | readable code, or the implicit conversions feature of Scala
           | (which also, IMO, produces less readable code, but they've
           | addressed a lot of the major problems with it).
        
           | syrrim wrote:
           | recommend setting up tests for your code s/t failures block
           | deployment. can catch categories of bugs beyond typing errors
        
       | w4rh4wk5 wrote:
       | I've seen this implementation of defer a few times now. I really
       | dislike calling this defer (like the keyword in Go) as the given
       | code won't be executed on return.
        
         | aartaka wrote:
         | Scoping defer to a block is actually more useful and explicit
         | than function-exclusive that Go does, so I consider that a
         | feature.
        
           | w4rh4wk5 wrote:
           | No no, I think you misunderstood my critic. Defer working on
           | block-scope is fine; however, if I exit the block through a
           | return (or break), the deferred function is not called.
           | 
           | To my knowledge, you need a compiler extension to implement
           | this in C (or use a C++ destructor).
        
       | shakna wrote:
       | Well, there's a few things I should probably get around to adding
       | to CNoEvil[0] and ogw[1]... There always seem to be more every
       | few months when this project reappears.
       | 
       | [0] https://git.sr.ht/~shakna/cnoevil3/
       | 
       | [1] https://git.sr.ht/~shakna/ogw
        
       | pineaux wrote:
       | I feel compelled to try it out in a serious way and contribute to
       | it. I have strong knowledge of python and am learning C. Are
       | there good reasons -apart from attracting the ire of
       | c-programmers- to not use it?
        
         | aartaka wrote:
         | Author here. I'll be glad to accept any contribution that makes
         | C more readable, so PR away!
        
       | nanis wrote:
       | > if (argc above 1)
       | 
       | I give up.
        
         | aartaka wrote:
         | You're welcome!
        
       | fnord77 wrote:
       | I feel like this would have been cool 25 years ago
        
       | dfox wrote:
       | The code asumes that C17 has C++-style auto (https://github.com/a
       | artaka/pretty.c/blob/master/pretty.h#L11...), it does not (in C
       | auto is storage specifier that is equivalent to no storage
       | specifier).
        
         | aartaka wrote:
         | C17 doesn't have auto, but C23 does, and thus my
         | `__STDC_VERSION__ > 201710L` (notice the greater than sign, it
         | doesn't include C17 itself.)
        
           | dfox wrote:
           | Ha, apparently the N2310 working draft is not the last one :)
        
       | Alifatisk wrote:
       | If you find this interesting, you might like libcello.h aswell!
       | https://www.libcello.org
        
         | aartaka wrote:
         | Yes, it's one of the inspirations!
        
       | IgorPartola wrote:
       | For what it's worth this makes the same mistake that Python 2
       | did: string and bytes are not the same type and shouldn't be
       | treated as such.
        
         | umanwizard wrote:
         | What is your definition of "string"?
         | 
         | If it's "human-readable text", then fine, a string is not the
         | same thing as an arbitrary byte array.
         | 
         | But lots of languages don't enforce that definition.
        
           | bobbylarrybobby wrote:
           | Well that's the very thing: not enforcing that distinction is
           | the very mistake in question.
        
         | michaelsbradley wrote:
         | Given the nature of it (pretty.c) and the stated intention of
         | being "backwards-compatible with C and all of its libraries",
         | what would make more sense than sticking with C's multibyte
         | strings?
         | 
         | https://en.cppreference.com/w/c/string/multibyte
        
         | AlotOfReading wrote:
         | What do you consider the type of shell text, i.e. what's in
         | argv and what you get from subprocess output? It's not well-
         | formed utf8 strings because any random garbage can be in there,
         | yet tools like awk and grep are ubiquitous.
         | 
         | I'd argue that strings and bytes are the same general type, but
         | it's sometimes useful to give well-formed utf8 bytes a
         | different type internally. Rust gets this mostly correct with
         | OsString and String.
        
           | ryandrake wrote:
           | The way I understand it: Bytes are just bytes, until you
           | provide an encoding. Then they can be can be converted to a
           | string, if validly encoded. Taking an array of characters and
           | just treating it or casting it as a string is usually a bad
           | idea.
           | 
           | The thing I think Rust maybe goofed, or at least made a
           | little complicated, is their weird distinction between a
           | String and a str (and a &str). As a newbie learning the
           | language, I have no idea which one to use, and usually just
           | pick one, try to compile, then if it fails, pick the other
           | one. I'm sure there was a great reason to have two types for
           | the same thing, that I will understand when I know the
           | language better.
        
             | steveklabnik wrote:
             | I wrote a blog post that may help you!
             | https://steveklabnik.com/writing/when-should-i-use-string-
             | vs...
             | 
             | If you want to understand more deeply, the Rust Programming
             | Langauge, chapter 4, uses String and &String and &str to
             | talk about ownership and borrowing. Here's a link to the
             | start of that chapter: https://doc.rust-
             | lang.org/stable/book/ch04-00-understanding-...
        
               | ryandrake wrote:
               | How timely and helpful, thanks!
               | 
               | Your blog post is practical and clearly explains what to
               | do, when, which is helpful. What's confusing is _why_
               | Rust has the two types and why the language designers
               | decided it was a good idea to have to convert back and
               | forth between them depending on whether it was going in a
               | struct or being passed as an argument. I suppose the
               | "why" is probably better found in the Rust docs.
               | 
               | As a long-time C++ user, it seems like std::string vs
               | const char* all over again, and we somehow didn't find a
               | better way.
        
               | steveklabnik wrote:
               | Yep, that's exactly it: I wanted to focus purely on what
               | to do, rather than weigh it down with what's already in
               | the Rust book.
               | 
               | It's closer to std::string and std::string_view. But yes,
               | in a language with value and reference semantics, when
               | you also care about performance, you just can't do any
               | better: you need both types. Or at least, if you want the
               | additional correctness guarantees and safety provided by
               | communicating ownership semantics in the type. C gets
               | away with just char * but then you have to read the docs
               | to figure out what you're allowed to do with it and what
               | your responsibilities are.
        
               | AlotOfReading wrote:
               | In C++ terms, String is std::string, &str is
               | std::string_view. They're different things, but they can
               | appear similar.
        
               | brabel wrote:
               | A Rust `String` reference (i.e. &String) can always be
               | passed where `&str` is expected because `String` has a
               | `Deref<Target=str>` impl... in that sense they don't just
               | appear similar, they are polymorphic.
        
             | AlotOfReading wrote:
             | There may not be a single encoding for every byte in a
             | string. The encoding may not be knowable ahead of time. You
             | might be trying to extract strings from a random blob of
             | bytes with unknown origin. There's a thousand and one
             | different variations.
             | 
             | To give a real example, I once wrote some python scripts to
             | parse serial messages coming off a bus. They'd read the
             | messages, extract some values with regex, and move on.
             | 
             | Unfortunately the bus had some electrical bugs and would
             | intermittently flip random bits with no CRC to correct
             | them. From my point of view, no big deal. If it's in
             | something outside the fields I care about, I won't notice
             | it. If it's flipped something I do care about we have a bad
             | sample to drop or noise the signal processing will deal
             | with. Either way, it's fine. Python on the other hand cared
             | very much. I rewrote everything in C once I got
             | sufficiently annoyed of dealing with it and more
             | importantly explaining to others how they couldn't
             | "simplify" things using the stdlib APIs.
        
               | ptspts wrote:
               | Python stdlib conveniently supports both byte strings and
               | Unicode strings, even for regexps. Ther is no need to
               | migrate to any other language.
        
         | samatman wrote:
         | I don't agree. This doctrine presumes all of the following:
         | - String data will be properly encoded       - There is one
         | encoding of strings (UTF-8 usually)       - Validation must
         | occur when string data is created       - Truncating a logical
         | codepoint is never acceptable       - You may not do string
         | things to "invalid" bytes       - Proper encoding is the
         | beginning and the end of validation
         | 
         | None of these things are consistently true. It's a useful
         | practice to wrap validated byte sequences in a type which can
         | only be created by validation, and once you're doing that,
         | `Utf8String` and `EmailAddress` are basically the same thing,
         | there's no reason to privilege the encoding in the type system.
        
       | _benj wrote:
       | > The goals for Pretty C are:
       | 
       | > Provide so much syntactic sugar as to cause any C developer a
       | diabetes-induced heart attack.
       | 
       | :-D
        
         | spacedcowboy wrote:
         | As someone who just got diagnosed with type-1 diabetes (the
         | auto-immune variety, not the "you eat too much sugar" variety),
         | this was far more depressing than funny. I'm probably being
         | overly-sensitive, but man my life has gone to shit in the last
         | couple of years...
        
           | jdthedisciple wrote:
           | Sorry to hear.
           | 
           | Honest advice: I have heard fasting + healthy diet can
           | permanently fix diabetes (though I forgot which type)
           | 
           | Maybe try it? Good luck in any case!
        
       | pipeline_peak wrote:
       | For each looks convoluted, you shouldn't have to list the type.
       | 
       | It should be no harder than C#'s foreach(var i in list)
        
         | aartaka wrote:
         | Indeed, I might need to revisit foreach with type inference.
         | Should be totally possible.
        
       | sneed_chucker wrote:
       | Creating DSLs within C has a long tradition.
       | 
       | Stephen Bourne wanted to write his shell in ALGOL so badly that
       | he relentlessly beat C with its own preprocessor until it began
       | to resemble his preferred language.
       | 
       | https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
        
         | sheepscreek wrote:
         | Here is an example of what we wrote using it:
         | 
         | https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
        
         | Keyframe wrote:
         | This is not even half as bad as I expected it to be.
        
       | mjan22640 wrote:
       | Are variadic macros turning complete?
        
         | ay wrote:
         | Yes. https://github.com/rofl0r/chaos-pp
        
       | jcmontx wrote:
       | does this transpile to C or how does it actually work?
        
         | jdthedisciple wrote:
         | it's just aliases
         | 
         | preprocessor is using those #defines to replace tokens in the
         | code so it ends up as usual C
        
       | taylorius wrote:
       | Sorry for what is probably a stupid question. Does pretty.c act
       | as a preprocessor or sorts, converting your pretty.c script into
       | actual c, that is then compiled? Or is it a virtual machine that
       | interprets your pretty.c script?
        
         | aartaka wrote:
         | It's a set of C Preprocessor macros, so you don't even need to
         | somehow process the code--you just #include the header and hack
         | away as if it was regular C!
        
         | designed wrote:
         | Preprocessor of sorts. From the readme:
         | 
         | The goals for Pretty C are:
         | 
         | - Provide so much syntactic sugar as to cause any C developer a
         | diabetes-induced heart attack.
         | 
         | - Deprecate Lua, Python, JavaScript, Ruby and a dozen other
         | languages, because Pretty C is the ultimate scripting language,
         | but lightning-fast and strongly typed!
         | 
         | - Including only one header (yes, Pretty C is a header-only
         | library #include-able from arbitrary C file!) to turn any
         | codebase into a beginner friendly one.
        
         | wffurr wrote:
         | It's not a preprocessor or compiler. There's no binary. It's
         | just a bunch of C code in a header: macros, functions, etc.
         | that you can use to write different looking programs but that
         | are still C.
        
       | revskill wrote:
       | Or just use Ruby.
        
       | chris_wot wrote:
       | I'm waiting for someone to write a lambda calculus based C++
       | library that allows everything to be defined in terms of
       | function. Peano axioms and all.
        
       | jay-barronville wrote:
       | This project looks really cool! Unfortunately, there's just way
       | too much magic involved. In my humble opinion, C is simply not
       | the language for this level of magic--extreme use of macros (and
       | hidden behavior in general) is how you end up with hard-to-detect
       | (and hard-to-debug) bugs and security vulnerabilities. As cool as
       | this project looks, I'd never feel comfortable using it in
       | anything serious. A+ for the effort though!
        
       | kvirani wrote:
       | > Provide so much syntactic sugar as to cause any C developer a
       | diabetes-induced heart attack.
       | 
       | Haha love this!
        
       | stankot wrote:
       | This reminded me of ArnoldC
       | 
       | https://lhartikk.github.io/ArnoldC/
        
       | shiomiru wrote:
       | > max and min of two numbers.
       | 
       | Influenced by windows.h I see :)
        
       | cmcconomy wrote:
       | someone's salty about tiobe!
        
       | layer8 wrote:
       | Given the title, shouldn't that be #include "pretty.c" instead of
       | #include "pretty.h"?
        
       ___________________________________________________________________
       (page generated 2024-10-24 23:01 UTC)