1. 47
  1. 39

    In C:

    #define K * 1024
    

    DONE! Snorts cocaine.

    1. 15
      #define K <<10
      

      Shorter.

      1. 3

        Not by much, and runs the risk of some not understanding.

        1. 2

          I always find it weird that the precedence of << is lower than + in C. So 1 + 1 << 1 evaluates to 4 instead of 3 like I would expect.

          1. 4

            If I recall correctly, << and >> were added to the language after there were already a dozen or so C programmers, and they didn’t want to force everybody to re-learn the precedence rules.

            1. 2

              Reminds me of how the Makefile syntax was bugged, but by the time the author realized it, it was too late.

              1. 3

                You mean that you always have to use a single tab? I actually like that.

                1. 2

                  So many people like spaces. I like tabs.

                  1. 3

                    Tabs for indentation, spaces for layout works fine for me. Then the tab width doesn’t matter anymore (because let’s face it: 1 tab = 8 spaces is ridiculous).

                    1. 2

                      8-space tabs is the only way to write C.

          2. 1

            plus you get the benefit that the compiler will probably prevent you from applying it to a float or double.

            1. 3

              Under the circumstances, is that really a benefit?

            2. 0

              unsnorts cocaine

            3. 11

              This is also very easy to do generically in D:

              auto K(T)(T n) { return n * 1024;}

              D’s Uniform Function call Syntax and Compile-Time Function Execution allow you to use this elegantly and without any runtime overhead, without having to specify anything else:

              enum x = 512.K;

              enum y = 2048L.K; //(for long int type)

            4. 20

              prog21 was a great blog, really too bad he stopped :(

              I recommend browsing around there, if you’re not familiar with it.

              1. 8

                slumming with basic programmers in particular is one of my favourite programming blog posts from anyone.

                1. 3

                  Yeah it’s great. I ended up writing a script to package the whole blog into an shook for my kindle and read almost all the articles in one go. I’m not interested in writing forth but the authors level of pragmatism really spoke to me

                  1. 5

                    He writes about Python an J and other languages. From the impression left on me reading his blog in the past, it’s almost never about the language. He’s always making a larger point.

                    1. 1

                      Care to share? Book or script

                  2. 9

                    In Haskell:

                    data Bytes =
                        B
                      | KB
                      | MB
                    
                    instance (b ~ Double) => Num (Bytes -> b) where
                      fromInteger i B =
                        fromInteger i
                      fromInteger i KB =
                        fromInteger $ i * 1024
                      fromInteger i MB =
                        fromInteger $ i * 1024 * 1024
                    
                    instance (b ~ Double) => Fractional (Bytes -> b) where
                      fromRational r B =
                        fromRational r
                      fromRational r KB =
                        fromRational $ r * 1024
                      fromRational r MB =
                        fromRational $ r * 1024 * 1024
                    
                    Prelude> 100 B
                    100.0
                    Prelude> 100 KB
                    102400.0
                    Prelude> 100 MB
                    1.048576e8
                    
                    1. 3

                      I had no idea that was possible. Would you mind explaining a bit more in detail how it works? Do you need any language extensions?

                      1. 2

                        Do you need any language extensions?

                        You need flexible instances and ~, usually from TypeFamilies. These are things I have turned on by default in all of my application projects.

                        Would you mind explaining a bit more in detail how it works?

                        Warning: This explanation won’t work great if you (generic you, I know contivero knows Haskell) know literally zero Haskell. If that’s the case, uhhhh, buy my book? http://haskellbook.com

                        The Num and Fractional type classes are the basis for integral and fractional literals in Haskell. Every numeric literal in Haskell is polymorphic until the instance is resolved to a concrete type. 1 :: Num a => a and 1.0 :: Fractional a => a, where :: is type ascription and can be read as “has type.”

                        The (b ~ Double) isn’t strictly necessary if you don’t care about type inference. You could elide it and then the examples would look like:

                        Prelude> 100 B :: Double
                        

                        The essence of it is in the weird shape of the instance type: Num (Bytes -> b). We’re making an instance for numerical literals that is function-typed. We’ve said the inputs must be values from our Bytes type. This makes it so that in the expression: 100 B, the 100 gets resolved to a function which multiples the underlying number by the magnitude expressed in the data constructor passed to it as an argument, be it B, KB, or whatever else.

                        Now, hypothetically, we might know that we always want Bytes -> Double. If we don’t care about type inference, then our instance can be pretty simple:

                        instance Num (Bytes -> Double) where
                        

                        And we’re done, but that didn’t satisfy me. I wanted to see if I could get fancy syntax. If you try it unqualified, you get:

                        Prelude> 100 KB
                        
                        <interactive>:7:1: error:
                            • No instance for (Num (Bytes -> ())) arising from a use of ‘it’
                                (maybe you haven't applied a function to enough arguments?)
                            • In the first argument of ‘print’, namely ‘it’
                              In a stmt of an interactive GHCi command: print it
                        

                        GHCi will default the return type to () when the instance head is Bytes -> Double. So the stages of evolution are:

                        Bytes -> Double
                        Bytes -> b
                        (b ~ Double) => Bytes -> b
                        

                        The weird part is, (b ~ Double) => Bytes -> b and Bytes -> Double are the same type. b ~ Double just means, “b is Double”. However, that part of the type-checker runs at a different time than instance resolution.

                        What we really want is “instance local functional dependencies” and that’s exactly what this trick accomplishes. See more about functional dependencies here: https://wiki.haskell.org/Functional_dependencies

                        What the type (b ~ Double) => Bytes -> b lets us do is “capture” uses of function-typed numerical literals whose inputs are Bytes and that have a return type whose type is unknown, then we supply a concrete type for the return type with the type equality b ~ Double after the instance is already resolved.

                        You can’t overlap them:

                        Duplicate instance declarations:
                              instance (b ~ Double) => Num (Bytes -> b)
                                -- Defined at /home/callen/work/units/src/Lib.hs:40:10
                              instance (b ~ Integer) => Num (Bytes -> b)
                                -- Defined at /home/callen/work/units/src/Lib.hs:49:10
                        

                        But if the input types are different, totally kosher:

                        data Bytes =
                            B
                          | KB
                          | MB
                        
                        instance (b ~ Double) => Num (Bytes -> b) where
                          fromInteger i B =
                            fromInteger i
                          fromInteger i KB =
                            fromInteger $ i * 1024
                          fromInteger i MB =
                            fromInteger $ i * 1024 * 1024
                        
                        data BytesI =
                            Bi
                          | KBi
                          | MBi
                        
                        instance (b ~ Integer) => Num (BytesI -> b) where
                          fromInteger i Bi =
                            i
                          fromInteger i KBi =
                            i * 1024
                          fromInteger i MBi =
                            i * 1024 * 1024
                        
                        Prelude> 100 B
                        100.0
                        Prelude> 100 Bi
                        100
                        

                        An older application of this trick where I originally explored it: https://github.com/bitemyapp/buttress/blob/master/src/Buttress/Time.hs#L58

                        1. 2

                          Thanks! That’s a neat trick. The number acting as a function was one of the main things confusing me.

                    2. 7

                      template K*(n: SomeInteger): SomeInteger = n * 1024

                      This is what I use in Nim. 512.K, 64.K etc.

                      1. 6

                        I think C++ has a feature since C++11 where you can define your own constant type, like kilobyte, with a suffix.

                        1. 13

                          apparently, yes, it does https://en.cppreference.com/w/cpp/language/user_literal

                          I’m no c++head but

                          #include <iostream>
                          
                          unsigned
                          operator"" _K(unsigned long long n)
                          {
                            return n * 1024;
                          }
                          
                          int
                          main()
                          {
                            std::cout << 64_K << '\n';
                            return 0;
                          } 
                          

                          works as expected.

                        2. 4

                          F# has units of measure, which seems really cool. You could write units for B, KiB, MiB, etc.

                          1. 3

                            So does Kawa Scheme. It’s pretty elegant how they rewrite a numerical suffix into an expression.

                          2. 3

                            It should be Ki to be proper SI “prefix”. And that is the reason why I think that it is not so great idea.

                            1. 4

                              “kibibytes” sounds so stupid. SI can FO.

                              1. 3

                                While I agree, they were first with K meaning 1000, so we needed something to differentiate.

                                1. 4

                                  Except it’s ‘k’ that means 1000, as in ‘km’ for kilometers. ‘K’ isn’t used, so it’s therefore available as an alias for ‘Ki’ or ‘KiB’. A correctly written ‘kilo-’ figure will use ‘k’, not ‘K’.

                                  The other prefixes (‘M’, ‘G’, and so forth) were ambiguous, though, so it’s important to write ‘MiB’ and ‘GiB’ when we mean that.

                                  1. 2

                                    That’s ok, we can just append a K to indicate another multiplication with 1,024.

                                    So 1 KiB = 1K.

                                    1 MiB = 1KK.

                                    1 GiB = … wait, I think I see a problem here.

                                    1. 1

                                      Well, the first problem is that you’re using ‘K’ to mean ‘KiB’ as well as just the ‘Ki’ prefix, in the same term — which is just asking for grammar nazis to come out of the woodwork.

                                2. 1

                                  I mean, this way people can pick and choose. Storage sellers especially are happy to adopt the (correct) SI definition for defining how many bytes their hard drives and memory cards contain.

                              2. 1

                                A related topic that I’ve been running into a lot recently: converting size-suffixed strings into integers, e.g. convert("4K") == 4096. It’s unsurprising that I have to write this routine myself in C, but does anyone know of any languages that provide this in their standard library? (The most “batteries-included” language I deal with regularly, Python, does not as far as I can tell.)

                                1. 1

                                  I’d use regular expressions to deal with this.

                                  1. 9

                                    Now you have 2K problems.

                                2. 1

                                  If you like this idea and are using C++14, nholthaus has a really cool library that expands this to most scientific units available. Compiler enforced units to make sure your math is correct is awesome!