CppCon 2018: Andrei Alexandrescu “Expect the expected”

Sdílet
Vložit
  • čas přidán 31. 10. 2018
  • CppCon.org
    -
    Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/CppCon/CppCon2018
    -
    Writing code that is resilient upon errors has always been a pain point in all languages. Exceptions are the politically correct means to signal errors in C++, but many applications still resort to error codes for reasons related to ease of understanding, ease of handling errors locally, and efficiency of generated code.
    This talk shows how a variety of theoretical and practical artifacts can be combined together to address error codes and exceptions in one wholesome, simple package. The generic type expected<T> can be used for both local (error-code-style) and centralized (exception-style) manners, drawing from the strengths of each.
    -
    Andrei Alexandrescu, The D Language Foundation
    Vice President
    Andrei Alexandrescu is a researcher, software engineer, and author. He wrote three best-selling books on programming (Modern C++ Design, C++ Coding Standards, and The D Programming Language) and numerous articles and papers on wide-ranging topics from programming to language design to Machine Learning to Natural Language Processing. Andrei holds a PhD in Computer Science from the University of Washington and a BSc in Electrical Engineering from University "Politehnica" Bucharest. He is the Vice President of the D Language Foundation.
    -
    Videos Filmed & Edited by Bash Films: www.BashFilms.com
    *-----*
    Register Now For CppCon 2022: cppcon.org/registration/
    *-----*

Komentáře • 53

  • @mrlithium69
    @mrlithium69 Před 5 lety +77

    I love the way he presents! Very conversational, and natural, while still hitting all the salient details and not just outright repeating whats on the slides. And funny, throwing in jokes - not nervous at all. He also anticipates our possible thinking stumbling blocks and even addresses the natural tangential side-thoughts. Totally comprehensive. And from a non-native speaker of English, it's all the more impressive. What a legend! (much better than Titus - total opposite in fact) - almost on Bjarne's level. Big fan of his contributions too. He really sees the big picture and doesn't get distracted.

    • @andralex
      @andralex Před 5 lety +15

      Thank you very much!

  • @acf2802
    @acf2802 Před 3 lety +8

    3 years later and this still is in proposal.

    • @Norhther
      @Norhther Před 3 lety +1

      Love the idea, hate the semantics

  • @user-ov5nd1fb7s
    @user-ov5nd1fb7s Před 5 lety +29

    "I heard you not saying", LOL.
    I am going to use this quote from now on.

  • @Elite7555
    @Elite7555 Před 4 lety +11

    Andrei is a phenomenal speaker!

  • @Omnifarious0
    @Omnifarious0 Před 5 lety +8

    He's absolutely right about how expected should behave, down to the last detail. I really hope the standards committee makes it and does it the way he recommends, right down to not having operator *.
    I've been thinking through how to do error handling for a hypothetical C++ wrapper to the POSIX/Linux api. I came to the exact same conclusion for how it should be done.
    Compilers are good enough at flow analysis to emit diagnostics if you never check things like `expected`, or even if you ignore any exected.

  • @belst_
    @belst_ Před rokem +2

    I think a solution to expected would be to annotate functions returning that as nodiscard, that way you would at least get a compiler warning if you just ignore the return type
    edit: ok exactly that question was asked right at the end

  • @WiktorWandachowicz
    @WiktorWandachowicz Před 5 lety +1

    Big possible change at 33:55 wrt. exceptions - and at 34:00 I even did the clapping myself :)
    To create exceptions and use them for handling errors, *without* throwing the exceptions immediately is IMHO a really great idea! Such a simple solution: a function should return a real value or exception object. Simple, powerful, beautiful. Go, JF!

  • @wintermute701
    @wintermute701 Před 4 lety +2

    34:45 Is there any difference between calling the copy constructor with placement new vs. using a member initialization list, i.e. : yay(rhs) ?

  • @RaaynML
    @RaaynML Před 4 lety +4

    22:50 does anyone have a link to the function by Herb Sutter mentioned?

  • @aliancemd
    @aliancemd Před 5 lety +14

    Around ~ minute 4 it was clear that this will sound like C++'s version of Rust's "Result".

    • @seidenada526
      @seidenada526 Před 5 lety

      I've just read about Rust error handling and the ? operator is pretty neat (nothing like the ternary in C++ for those wondering). With std::expected it would be like calling .value() just after receiving one std::expected from a function, i.e. auto a = openFile("..").value(); What I liked in Rust is that, if opening the file failed, the calling function would just propagate the error in it's own returned Result, when in C++ you enter the alternative path of exception propagation.. It would be more verbose to have the Rust-like behavior in C++, i.e. auto a = openFile(".."); if (!a) return unexpected(a.error()); Too much typing =p

    • @aliancemd
      @aliancemd Před 5 lety +4

      ​@@seidenada526 If you are curious, I recommend also checking "failure" on "crates.io", it's error chaining made easy :)
      Dropbox did say that they observed that their Rust code is not only free of memory management issues but also has a lot less bugs in general - my guess is that because you have to handle the error case in Rust and you just slap "?" everywhere you want to propagate the error and handle it where you want to recover for example, this way it's very simple to handle all error cases(failed to open file? failed to parse the JSON from it? failed to read an int value from that JSON? No problem, just slap "?" and handle all of it :) ).

  • @blenderpanzi
    @blenderpanzi Před 5 lety +1

    If you write your application using expected with exception handling deactivated, then .value() is surly also undefined behavior?

  • @eLBehmo
    @eLBehmo Před 4 lety

    At 50:00: For those who want the returned and unchecked error to throw (in the destructor of expected): yes I implemented such a solution and 'it works'. But you generally don't need it if you mark your functions nodiscard and check your warnings!

  • @masondeross
    @masondeross Před 11 měsíci +1

    Update: We finally have expected in C++23!

  • @timseguine2
    @timseguine2 Před 5 lety +3

    I finally decided that Andrei's voice reminds me of Triumph the insult comic dog. "This code is really great... for me to poop on!"

  • @OperationDarkside
    @OperationDarkside Před 5 lety +3

    1. Great and entertaining talk.
    2. There's a ')' missing in slide 30, I think.

    • @serengeor5148
      @serengeor5148 Před 5 lety +1

      Yeap, I noticed it almost instantly and then I thought it was put after assert by mistake (not the case though).

  • @andrybak
    @andrybak Před 4 lety

    At 45:59 - is desctructor of temporary `E t` called on scope exit?

  • @MaceUA
    @MaceUA Před 5 lety

    I don't understand why they discarded the approach with storing an std::exception_ptr instead of some template argument E inside the Expected. If I remember correctly, that's what Andrei initially proposed a few years ago when presenting the idea of Expected. That approach looked much cleaner (no need to specify two template arguments) and more flexible (you could store any kinds of exceptions in the Expected, even if the function "throws" multiple unrelated exception types).
    Is there an explanation why this decision was made now?

    • @xfreeman86
      @xfreeman86 Před 5 lety

      boost::result defaults the second type parameter to std::error_code. If you want, you can declare a type alias that does that for std::expected

    • @kuhluhOG
      @kuhluhOG Před 4 lety

      MaceUA I think because of error codes (aka ints).

  • @maximetournier8716
    @maximetournier8716 Před 5 lety +7

    where is monadic bind operator?

  • @oof-software
    @oof-software Před 2 lety +1

    Wouldn't returning `expected` show less intention than returning `optional`?
    Since in the end both return types say 'this function might return an error or nothing'.
    My guess is, that `expected` would be preferred only for homogeneity among other return types.

    • @jonaskoelker
      @jonaskoelker Před 8 měsíci

      > Wouldn't returning `expected` show less intention than returning `optional`?
      I'd say that depends on whether the actual name of `error_type` indicates clearly that it represents an error. If the error type is `int`, that is not the case. Although that depends a lot on what customs and conventions will get adopted in the wild.
      You probably can and want to define a "expected::flatMap(f: function from A to expected) returning expected", which will let you sequentially combine computations which return `expected` (not calling `f` if the step that tried to produce an `A` failed). Treating `void` specially would make `flatMap` less powerful.
      I guess I'm making the homogeneity-is-good argument-though more for programming capability reasons that easy readability reasons.

  • @zhaoli2984
    @zhaoli2984 Před 5 lety +2

    it is mimicking the NAN convention in floating point computation.

  • @erikvanvelzen
    @erikvanvelzen Před 5 lety +2

    37:55 I'm not 100% sold on the constructor-based thing. Personally I would have a private constructor with named constructors std::expected::ofValue and std::expected::ofError. Though I see that's a bit more verbose.
    edit: I see at 47:50 something like that exists, so you can use either expected() or unexpected()

    • @xfreeman86
      @xfreeman86 Před 5 lety

      @Ziggi Mon the copy and unexpected constructors are more specific, and the default constructor cannot be instantiated anyway if T is not default constructible (it is instantiated only when someone tries to use it, not when the class is instantiated). You only need enable_if to control the overload set of valid instantiations

  • @Mirality
    @Mirality Před 5 lety +15

    47:56 I wonder if the missing parenthesis was unexpected...

  • @inferioaltio
    @inferioaltio Před 5 lety +1

    Can someone explain, why did they use placement new instead of simple initializing in constructors?

    • @YourCRTube
      @YourCRTube Před 5 lety +2

      Because this is the way to construct an object without allocating memory - union is C-thing and it does not know about constructors, but it has the memory already allocated.

    • @inferioaltio
      @inferioaltio Před 5 lety

      ​@@YourCRTube Still don't really understand why expected(const T& rhs) : yay(rhs) {} is worse than placement new, in both cases yay will be constructed once (and I suppose memory for yay will be allocated only once as well)

    • @ARTijOMS
      @ARTijOMS Před 5 lety +1

      I believe the primary reason it is written this way is so that union is not mistaken for class - placement new is the "union style" of starting the lifetime of an object. From the standard: [Note: In general, one must use explicit destructor calls and placement new-expression to change the active
      member of a union. -end note]

    • @damianjarek1974
      @damianjarek1974 Před 5 lety +3

      Non-trivial data members of unions have to be constructed that way (and you have to call the destructor on your own as well!). Construction initialization for unions is only allowed for trivial types.

    • @inferioaltio
      @inferioaltio Před 5 lety

      @@damianjarek1974 I did some research and found this reply on stackoverflow stackoverflow.com/questions/33058717/do-unrestricted-unions-require-placement-new-and-a-constructor-definition
      basically it says that in this particular case both ways are correct.

  • @MaceUA
    @MaceUA Před 5 lety

    Slide 28: it might be better to use std::conjunction to short-circuit the expression inside enable_if.
    Also, another part of homework for implementers: make this swap() function conditionally noexcept, where it can be. That could help some other generic code to be more efficient.

  • @vvviiimmm
    @vvviiimmm Před 5 lety +9

    So if anyone familiar with IO[A, E] or even Either[A, B] types in FP -- this is essentially the same with a lot of C++ noise. Furthermore, the proposed implementation doesn't compose well (52:12)

    • @vorpal22
      @vorpal22 Před 5 lety +1

      Coming back to C++ after not using it in over a decade and working predominantly in Java / Scala, I am amazed at how utterly crappy std::optional is.

    • @vorpal22
      @vorpal22 Před 5 lety +2

      @D X ​ I started catching up with all the changes made in C++11, 14, and 17 just maybe six months ago, and I'm really loving it, which surprised me, because C++98 is what originally put me off of programming for a long time (until I learned Python). I love template metaprogramming in particular (even though I have a huge ton to learn on that subject) and playing around with constexpr to see what I can do with it.
      I agree that STL types compose / inherit very well in most cases. std::optional seems like the exception rather than the rule, but that may be because the STL is completely iterator based, and giving optional iterators would work (and I'm surprised they haven't done it - it would make it fit much better into the STL) but admittedly would look weird.
      I think that many C++ programmers fail to understand how much optional types have changed programming with pointers / references because optional in C++ is so limited. It really seems to offer little benefit over using nullptr, unlike, say, Java or Scala, where you can just easily chain together transformations and filters over the optional types so nicely and really see the benefit of having a monad of optional.
      Wasn't boost::optional more advanced than stl::optional? I should look into that as a point of curiosity.
      Hmmm... it would be a fun challenge to make an optional type that works with iterators. Another project for me to think about.

    • @YourCRTube
      @YourCRTube Před 5 lety +3

      @@vorpal22 Don't forget optional, as an std thing, is _less then an year old!_ Monadic interface is proposed (there is a paper) and probably optional of reference will come as well. People like optional a lot, so it will improve for sure.

    • @vorpal22
      @vorpal22 Před 5 lety

      @@YourCRTube How long has it been in boost? From the boost optional page, it looks like at least four years, and possibly more than 10. I really hope that there are some improvements in mind for C++20. (I'm intrigued and terrified by C++20... it seems like there will be many new things there and I'm just catching up to 14 and 17.)
      I'm glad to hear that optional is well liked. I honestly have no idea... I'm just starting to get into the C++ community. I felt very intimated by the fact that I hadn't programmed in C++ for so long, but I'm starting to feel more comfortable and all the C++ programmers I've chatted with online have been very patient and helpful.
      I'd really like to go to some C++ conferences in the next year... CppCon and C++ by Sea both are calling to me. Do you have any recommendations?

    • @vorpal22
      @vorpal22 Před 5 lety

      @@YourCRTube BTW... thanks for pointing me towards the monadic interface paper! I'm going to sit down and read it over. I'm definitely intrigued.

  • @zhaoli2984
    @zhaoli2984 Před 5 lety +1

    yet another way to handle errors in cpp?

  • @fnc12
    @fnc12 Před 10 měsíci

    I really expected an expected to be inside the other expected but Andrei failed my expectations!

  • @myverynow
    @myverynow Před 5 lety

    found local choreography normal (cause they do java instead of c++) LOL

  • @user-ov5nd1fb7s
    @user-ov5nd1fb7s Před 5 lety +1

    The guy is funny