CppCon 2016: Ben Deane “Using Types Effectively"

Поділитися
Вставка
  • Опубліковано 12 вер 2024
  • CppCon.org
    -
    Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/cpp...
    -
    C++ has a pretty good type system, and modern C++ gives us a greater ability than ever before to use that type system for good: to make APIs easier to use and harder to misuse, to make our datatypes more closely express our intent, and generally to make code safer, more obvious in function and perhaps even faster.
    This is an interactive session - incorporating games played between presenter and audience, even - taking a look at choices available to us as datatype and API designers, and examining how a little knowledge about the algebra of algebraic datatypes can help. We'll see why std::optional and (hopefully soon) std::variant will quickly become an essential part of everyone's toolbox, and also explore how types can be used to express not just the structure of data, but also the behaviour of objects and functions.
    -
    Ben Deane
    Principal Software Engineer, Blizzard Entertainment
    Ben has been writing games for almost 20 years, and in C++ for most of that. He is currently a Principal Engineer at Blizzard Entertainment where he works on the Battle.net team. He's always looking for useful new techniques in C++, and he likes functional programming.
    -
    Videos Filmed & Edited by Bash Films: www.BashFilms.com
    *-----*
    Register Now For CppCon 2022: cppcon.org/reg...
    *-----*

КОМЕНТАРІ • 53

  • @wesofx8148
    @wesofx8148 7 років тому +12

    Wow, optionals and variants are what I've always wanted and I had no idea. No mare enum/union non-sense and sentinel value non-sense.

  • @LooJulian
    @LooJulian 7 років тому +6

    Safe brilliant sharing of talk. Thanks Ben Deane and all.

  • @arisweedler4703
    @arisweedler4703 2 роки тому +1

    It was a bit hard to wrap my head around 13:20, but I figured it out smoothly eventually.
    An “instance of a function” draws a line from “a value in the world of args” to “a value in the world of results”. To describe a function in terms of types completely, you need an instance of the function for EVERY arg. A complete function has instances, and each instance line can end in different ways.
    So for every “value in the world of args”, you have additional types.

    • @arisweedler4703
      @arisweedler4703 2 роки тому

      Ramblings:
      The number of “types a function has” when the cardinality of is 1 . When the cardinality of is 2, you can pretend it is 2 uncurried functions. Both are equivalent (in terms of cardinality) to the first case. 1 value of argument to any value of the results function. Take the Cartesian product of these two functions. So… ^2.
      This pattern repeats. And you are left with the cardinality of a function’s type is ^.
      It’s cool. Because when there are two values for arguments, any single function draws two lines from the world of args to the world of results. And you can draw each line ways.

    • @arisweedler4703
      @arisweedler4703 2 роки тому

      If there is a pointer from a single instance of arg to each instance of result, there are result pointers. Or we can declare this to be a single “mega pointer” from arg to “world of results”.
      A function is a “mega pointer” from each value of arg to “the world of results”. |result| multiplied by itself |arg| times.
      Taken a step further… a function is a mega pointer from “the world of args” to “the world of results”. |result|^|args|.
      It’s interesting to think about currying now because if you could “de-curry” a function call with |arg|=2 into 2 function calls with |arg|=1, then this whole thing becomes a lot more clear!!! Each un-curried function has a mega pointer into .

    • @arisweedler4703
      @arisweedler4703 2 роки тому

      Ben Deane explains it again at 53:00 in the Q&A section

  • @NebuPookins
    @NebuPookins 2 роки тому +1

    It's good that this topic is becoming more mainstream, but there are a few errors in his talk. For example, the type `void` in C++ has cardinality 1, not 0. A type with cardinality 0 is called a "bottom type", and is the subtype of all other types. I'm not a C++ guru, but my understanding is that C++ does not have a bottom type, although some of its functionality can be replicated with the `noreturn` attribute from C++11.

  • @jjurksztowicz
    @jjurksztowicz 7 років тому +2

    Great talk, very applicable to other slightly less statically typed environments too.

  • @AxelStrem
    @AxelStrem 7 років тому +11

    "functional programmers keep saying 'map' and 'filter'..." - but these functions actually are 'map' and 'filter', semantics are completely different from 'transform' and 'remove_if'

    • @TomaszWota
      @TomaszWota 7 років тому

      Can you elaborate?

    • @AxelStrem
      @AxelStrem 7 років тому +4

      What I mean is std::transform takes an output iterator and writes the transform result to wherever you want, including original container, so (in other words) it deals with "memory". Ben's transform on the other hand returns resulting container as a value, so it has this functional stateless taste to it, it deals with "values" - this is exactly what 'map' function does.
      Same goes for std::remove_if - it cannot even actually remove elements due to container/iterator separation, while Ben's remove_if gives you a filtered ready-to-use container.

    • @AxelStrem
      @AxelStrem 7 років тому +5

      I don't want to pick on Ben though, the talk is pretty solid, I liked it:)

    • @TomaszWota
      @TomaszWota 7 років тому +3

      Ah, yes, now that you've stated the obvious it indeed seems... obvious. Made me feel stupid, but in a good kind of way. Thanks. :)
      I liked it too, but I'm of two minds about the idea of "STL2" with variants and optionals all over the place. If it happened to provide better performance, or heck - at the very least not worse - sure, I think I'd go for it.
      I think I'd generalize the point to the whole standard library, actually. But I just can imagine the mess of having effectively two standard libraries - one with and one without the optionals/variants...
      Then the nightmarish visions appear: some functions having sentinel values/error codes, some setting errno, some returning variants or optionals, some throwing exceptions... The worst thing is we're already living the nightmare. :P
      Plus, I don't really see variants replacing exceptions. Although it is interesting to ponder.

  • @AdasPK
    @AdasPK 7 років тому +3

    That is one of the best talks I have seen!

  • @gowtham236
    @gowtham236 Рік тому +1

    Terrific talk, highly recommend.

  • @alexweej
    @alexweej 7 років тому +13

    Great talk but the Q&A is, as always, really annoying when people don't get a mic...

  • @selvakumarjawahar
    @selvakumarjawahar 8 років тому +21

    very useful practical talk... good

  • @wpavada3247
    @wpavada3247 7 років тому +1

    This is applicable to reduce domain at compile time and also reduce testing process. We should not misunderstand this with run time verification(what i mean is still run time logic has to be tested).

  • @TomaszWota
    @TomaszWota 7 років тому +10

    More of things like this, please. :)

  • @danielrhouck
    @danielrhouck 7 років тому +4

    You said you wouldn’t use the M-word, but then you did a couple times starting at 47:41 (which is in the Q&A, so it’s okay).
    Otherwise great talk!

  • @fettyplayground7241
    @fettyplayground7241 6 років тому +1

    Brilliant talk.

  • @iforve
    @iforve 7 років тому +1

    Brilliant talk, thank you

  • @cmdlp4178
    @cmdlp4178 7 років тому +2

    What if the ``?:`` is improved that ``a ? b`` makes an ``optional`` and ``a : b`` returns the contents of a when not empty else b?

  • @Manquia
    @Manquia 7 років тому

    When this enters the std I'll definitely give it a shot.

  • @Danielle_1234
    @Danielle_1234 7 років тому +4

    Can someone explain to me why char f(bool) is 256^2 instead of 2*256? Am I misunderstanding that the number is supposed to represent the number of possible combinations? I can make a truth table that shows all possible combinations for char f(bool) and it comes out to 512 possibilities.

    • @xXH3ll5xB3llXx
      @xXH3ll5xB3llXx 7 років тому +2

      Each value of the bool can be mapped to any of 256 values and to get a complete function you can take any combination of two mappings. So for a given mapping of one value there are 256 possible mappings for the other giving 256 * 256 or 256^2 combinations.

    • @Danielle_1234
      @Danielle_1234 7 років тому +4

      Oh, I see. It's counting the total possible number of functions, not the total number of input and output combinations.

    • @cgoobes
      @cgoobes 6 років тому

      I don't understand why this is significant. In the end, that function can map only one of 2 values to one of 256 outcomes. Only one input can exist at a time, and only one output can exist at a time, so 512 is the only meaningful number as it represents the total number of possible mappings.

    • @jakearkinstall1694
      @jakearkinstall1694 6 років тому +1

      @cgoobes But the discussion is about how many possible functions there are that map one of two values to one of 256 values. Simplify this and turn it into a function from a bool to an enum{ A, B, C }. Here are the possible functions:
      1) False => A, True => A
      2) False => A, True => B
      3) False => A, True => C
      4) False => B, True => A
      5) False => B, True => B
      6) False => B, True => C
      7) False => C, True => A
      8) False => C, True => B
      9) False => C, True => C
      Sure there is only one input at a time, and one output at a time, but that isn't relevant - and 6 isn't the meaningful number here. What you're doing is picturing a set of functions in a strange way:
      1) False => A
      2) False => B
      3) False => C
      4) True => A
      5) True => B
      6) True => C
      But none of these are functions, they're just statements in need of coupling.

    • @siergiejriaguzow1729
      @siergiejriaguzow1729 5 років тому

      I'm also having problems with this combinatorics stuff but maybe this will help to understand:
      1st function:
      f(false) - 122, f(true) -> 123
      2nd function:
      f(false) - 122, f(true) - 124
      3rd function
      f(false) - 122, (true) - 125
      .. 256 functions like that.
      This already gives 256. But for another function it can be that for f(false) it will return 199 and same as the previous one for true. This gives another 255. Yet another function will return 255 for false and same results as the previous for true. So for each true -> N (256 combinations) there are false -> N (256 combinations) of functions which return same stuff for true. Hence 256^2. Easy. Eh.. Not really.

  • @climatechangedoesntbargain9140
    @climatechangedoesntbargain9140 5 років тому +1

    Thanks for the Phantom

  • @andik70
    @andik70 8 років тому +1

    11:38 maybe you have to define the function with a 'noexcept'? Otherwise technically there are more possibilities.

    • @origamibulldoser1618
      @origamibulldoser1618 8 років тому

      Was thinking the same thing. Anybody else look at that connection modelling class and go "this looks exactly like what I wrote yesterday." ?

    • @TomaszWota
      @TomaszWota 7 років тому

      +1 for remembering about exceptions, however - with exceptions, as you very well know, technically the function doesn't properly return (a value) even though the stack unwinding happens. So I think this shouldn't be counted.

  • @perfectionbox
    @perfectionbox 3 роки тому

    so i would use std::holds_alternative to test for a particular "enum" inside a variant? How much slower is that than just comparing an enum?

    • @chri8686
      @chri8686 2 роки тому

      You can use holds_alternative to test for a specific type. If you want to process a variant, a more general approach is to use std::visit. Take a look at the function "overloaded" in the example on cppreference's std::visit page.

  • @anthonyhuang8914
    @anthonyhuang8914 6 років тому

    eye-opened talk

  • @bioai7507
    @bioai7507 5 років тому

    thanks to ben

  • @italoaugustooliveira9664
    @italoaugustooliveira9664 3 роки тому

    20:30 looks like a performance nightmare.

  • @dnaphysics
    @dnaphysics 6 місяців тому

    Disagree with "bool f(bool)" having only 4 values in C++.
    I say infinity, e.g.
    bool f(bool b) { return random()&b; }
    or
    bool f(bool b) { return date()&b; }
    A function can have an infinite number of definitions in C++.

  • @dlwatib
    @dlwatib 5 років тому +2

    My experience of writing code for compiled languages is that it's like working with a straitjacket on. My errors were rarely in the code itself, it was syntax errors in the arcane, inscrutable language used to express the types. The code he put up to express phantom types is complete gibberish to me. I don't think I've ever had a bug where I've said "I wish I had a type system to save me from making this same error in the future." I never mix up fixed point and floating point numbers, for instance. When I add a character to a number, it's deliberate, and getting the type system to understand my intention is just getting in the way of what I want to get done. I have, however, wished for more expressive loop constructors so I don't have to ever say again:
    for (i=0; i

    • @seditt5146
      @seditt5146 5 років тому +4

      is... is this like a troll post or joke or something?

  • @tshev
    @tshev 3 роки тому

    Not for every value of `double` you can compute min: ua-cam.com/video/ojZbFIQSdl8/v-deo.html

  • @MasterHigure
    @MasterHigure 6 років тому

    25:30 While it's always nicer to have a compile-time check, this kind of thing (like sanitized vs unsanitized) is the point behind Hungarian notation. While it can't make the compiler check for you, correct Hungarian notation here would be to have some prefix on all unsafe string variable names (as well as functions returning unsanitized strings) and some other prefix on all sanitized string variables (and functions). This makes it as easy as it can be to spot that you're using an unsanitized string somewhere you shouldn't (and you can possibly even write tools to help you). Unfortunately, Hungarian notation has been gravely misunderstood, which is why so many hate it.

    • @TheR971
      @TheR971 5 років тому +1

      So basically an unenforced, convention based monad? Why not go full monadic?

  • @babgab
    @babgab 7 років тому

    So many templates. Wonder how using variants and phantom types affects compile time?

  • @ShawnHCorey
    @ShawnHCorey 5 років тому

    Picking nits: Making _Invalid_ States Unrepresentable
    Illegal should never be used unless it is against the law for real.

    • @TheR971
      @TheR971 5 років тому +1

      The state is illegal in the laws you construct. In the end, I am the sovereign of my code laws!

  • @RogasTV
    @RogasTV 7 років тому +8

    No no no, this guy used The Idiotic Notation for members (m_)... it makes reading so less joyful.

    • @TheR971
      @TheR971 5 років тому

      You are the first person I hear copmlain about the m_ notation! I find it quite nice personally as it makes me think less about naming.