Formal Review Tribool

The review of Douglas Gregor's Tribool library begins now and runs through Saturday, May 29. Here is a short introduction to the library: The 3-state boolean library contains a single class, boost::logic::tribool, along with support functions and operator overloads that implement 3-state boolean logic. The tribool class acts like the built-in bool type, but for 3-state boolean logic. The three states are true, false, and indeterminate, where the first two states are equivalent to those of the C++ bool type and the last state represents an unknown boolean value (that may be true or false, we don't know). When reviewing the library, please remember to include: * What is your evaluation of the design? * What is your evaluation of the implementation? * What is your evaluation of the documentation? * What is your evaluation of the potential usefulness of the library? * Did you try to use the library? With what compiler? Did you have any problems? * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? * Are you knowledgeable about the problem domain? And finally, every review should answer this question: * Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. The library is available in the Boost files area as tribool-20031026.tgz Thank you, Thomas Witt -- Thomas Witt witt@acm.org

"Thomas Witt" <witt at acm dot org> wrote:
The review of Douglas Gregor's Tribool library begins now and runs through Saturday, May 29.
I think the library should be accepted in Boost (problems with MSVC family of compilers need to get solved first, though). I had some comments to the library in the past. Few new isuues and nitpicks are bellow. /Pavel ____________________________________________ 1. It may be useful to have header with forward declarations tribool_fwd.hpp. ____________________________________________ 2. Just thought: shouldn't tribool name be fetched via "using" into boost namespace? I see little chance for possible clashes. ____________________________________________ 3. docs: the "Home" link on the top is broken. Actually all of them. Links to headers in reference are invalid. ____________________________________________ 4. BOOST_TRIBOOL_THIRD_STATE.html should say where (i.e. no namespace of its own) the new name get declared. An example could be here. The file name may be lowercased. ____________________________________________ 5. Question: will tribool play well with initialization library? (from Thorsten Ottosen) ____________________________________________ 6. swap() member can be added. ____________________________________________ 7. serialization support (probably non-intrusive version) should be added. Serialization of optional<> can be taken as example. ____________________________________________ 8. why is tribool() initialized to false and not indeterminate? Some explanation should be in docs. ____________________________________________ 9. Silly question: is there way to use ternary operator somehow to initialize tribool conditionally: tribool t(x ? true : indeterminate); // something like that ____________________________________________ 10 compiling test with Intel C++ 7.0 I get errors: tribool_test.cpp C:\Temp\tribool\libs\logic\test\tribool_test.cpp(18): error: more than one operator "||" matches these operands: function "boost::logic::operator||(boost::logic::tribool, bool={bool})" function "boost::logic::operator||(boost::logic::tribool, boost::logic::indeterminate_keyword_t)" operand types are: boost::logic::tribool || int assert(!x); I get similar errors for VC6. OTOH BCB 6.4 compiles and runs OK. ____________________________________________ 11. Naming nitpick: maybe function default_indeterminate_name() would have better name get_default_indeterminate_name(). ____________________________________________ EOF

----- Original Message ----- From: "Pavel Vozenilek" <pavel_vozenilek@hotmail.com>
1. It may be useful to have header with forward declarations tribool_fwd.hpp.
Is tribool big enough that it matters? I'm not opposed to having a forward header, but it seems unnecessary.
____________________________________________ 2. Just thought: shouldn't tribool name be fetched via "using" into boost namespace?
I see little chance for possible clashes.
"indeterminate" would also need to be fetched, then. But this is a good idea.
____________________________________________ 3. docs: the "Home" link on the top is broken. Actually all of them.
Links to headers in reference are invalid. ____________________________________________
Will be fixed if/when tribool is added to the main tree.
4. BOOST_TRIBOOL_THIRD_STATE.html should say where (i.e. no namespace of its own) the new name get declared.
Good point!
An example could be here.
Okay.
The file name may be lowercased.
That's another BoostBook issue... we could fix it, but it introduces the possibility of more clashes.
5. Question: will tribool play well with initialization library? (from Thorsten Ottosen) ____________________________________________
Will look into this further.
6. swap() member can be added.
Any particular reason? std::swap is as efficient as it gets.
7. serialization support (probably non-intrusive version) should be added.
Serialization of optional<> can be taken as example.
Okay.
8. why is tribool() initialized to false and not indeterminate? Some explanation should be in docs.
Because it's meant to mimic a "bool"... you can drop a "tribool" in where there used to be a "bool" and the semantics won't change unless something you call can introduce an indeterminate value. This rationale is admittedly a little weak---I can see reasons for having an indeterminate initial value as well.
9. Silly question: is there way to use ternary operator somehow to initialize tribool conditionally:
tribool t(x ? true : indeterminate); // something like that
Unfortunately, I don't know of a way to get the conversions to work out right for that. If only we could overload the ternary operator :(
10 compiling test with Intel C++ 7.0 I get errors: [snip] I get similar errors for VC6.
I'll work on portability.
11. Naming nitpick: maybe function default_indeterminate_name() would have better name get_default_indeterminate_name().
Sure. Doug

"Douglas Gregor" <gregod@cs.rpi.edu> wrote:
1. It may be useful to have header with forward declarations tribool_fwd.hpp.
Is tribool big enough that it matters? I'm not opposed to having a forward header, but it seems unnecessary.
13 kB to parse. It will also make tribool lib 'similar' to other containers. /Pavel

Le mer 19/05/2004 à 19:23, Thomas Witt a écrit :
The review of Douglas Gregor's Tribool library begins now and runs through Saturday, May 29.
[...]
* What is your evaluation of the design?
There is not much to say. This library is small and implements a well-known concept. It is restricted to 3-state boolean and not extensible to bigger booleans but I don't think it is a flaw. Operators ! && || have the expected semantic for tribool. It is not true for == and != (the values could also be directly compared) but I don't have a strong opinion on what the "good" semantic is. So the design is good, except for this point imho: Why is tribool default-initialized to false? Since tribool is supposed to mimick bool, I would rather have no default value. Or if a default value is necessary for practical use, indeterminate seems to me to be a better choice than false.
* What is your evaluation of the implementation?
What is the purpose of safe_bool? I am asking the question because I was unable to compile with GCC a code as simple as: tribool a; assert(a == a); GCC complains that it "cannot convert `boost::logic::tribool' to `long int' for argument `1' to `long int __builtin_expect(long int, long int)'". It is obviously a problem caused by the definition of assert in the library; but still... With a bool conversion operator, there is no such problem. The definitions of the comparison operators are not optimal and the generated code is really bad. Something like this would be a lot more efficient (at least with GCC but there is no reason the other compilers would not benefit from this): inline tribool operator==(tribool x, tribool y) { if (indeterminate(x) || indeterminate(y)) return indeterminate; else // return x && y || !x && !y; return x.value == y.value; } This code is 8 asm instructions long. The one in the tribool library (the commented line) produces more than 70 asm instructions. The same is true for !=. The operators ! && || == != could also benefit from some bit-fiddling. For example, the ! operator could be rewritten as "x.value ^ 1 ^ (x.value >> 1)" in order to suppress all conditional instructions. However, contrarily to the previous rewriting, this one may hinder some compilers during the conditional branch reduction step. It all depends on the compiler and if the computed value is supposed to be stored (bit-fiddling is good) or tested (bad). So let's just forget about this idea. tribool_io.hpp refers to <boost/utility/noncopyable.hpp> but this header is not here. tribool_io_test.cpp should include <cassert>.
* What is your evaluation of the documentation?
The filenames are ugly but I suppose it is the fault of the automatic documentation generator. The relative links to the headers and tests are wrong. Other than these technical issues, I think the documentation is good. Concerning the tutorial, it should be mentioned the || and && operators are not short-circuiting operators contrarily to the boolean versions. I think it is important because it is a limitation of the implementation / language, not an inherent property of tribool. There is a problem with this example: assert(!(y == y)); // okay, because y == y is indeterminate Since y == y is indeterminate, !(y == y) is too, and consequently assert should not be okay, should it? And just before, there is this comment: // neither x nor y is false, but we don't know that both are true Shouldn't it be "neither x nor y is false and we know they are not both true"? The next comment also need to be modified.
* What is your evaluation of the potential usefulness of the library?
Such a type is really useful when manipulating objects that are not totally ordered. Indeed the result of "a < b" can be neither true nor false when the ordering is partial. The interval library would benefit from such a facility for example.
* Did you try to use the library? With what compiler? Did you have any problems?
I did convert my old programs that were using tribool to this new version. Except for the namespace change (from boost to boost::logic) and the assert(tribool) issue, I had no problem. I only tested with GCC 3.[345] for the time being. Please note that none of the logic/test files compiles with GCC. When a conversion to bool is added, there is no more problem (yes, it is still the assert(tribool) issue).
* How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
Only a quick reading through the documentation since I have been a user of the sandbox version (a bit modified) for a long time. I did not review the I/O however; I prefer to let people more aware about serialization issues do it.
* Are you knowledgeable about the problem domain?
Yes, as a user of this concept I know a bit about it. I also am a user of the 9-state boolean defined by the IEEE 1164 standard.
* Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
Yes. Best regards, Guillaume

----- Original Message ----- From: "Guillaume Melquiond" <guillaume.melquiond@ens-lyon.fr>
Operators ! && || have the expected semantic for tribool. It is not true for == and != (the values could also be directly compared) but I don't have a strong opinion on what the "good" semantic is.
Unfortunately, it depends on the application area. "if (x == true)" and "if (x == false)" act the same way with both semantics (because of the bool conversion), but "x == indeterminate" is always indeterminate in the current semantics (which can be surprising)... I decided to go with the current semantics because (1) it fit my application area and (2) it retains more information.
So the design is good, except for this point imho:
Why is tribool default-initialized to false? Since tribool is supposed to mimick bool, I would rather have no default value. Or if a default value is necessary for practical use, indeterminate seems to me to be a better choice than false.
In retrospect, this was clearly a mistake. It should (and will) be initialized to indeterminate.
* What is your evaluation of the implementation?
What is the purpose of safe_bool? I am asking the question because I was unable to compile with GCC a code as simple as: tribool a; assert(a == a); GCC complains that it "cannot convert `boost::logic::tribool' to `long int' for argument `1' to `long int __builtin_expect(long int, long int)'". It is obviously a problem caused by the definition of assert in the library; but still... With a bool conversion operator, there is no such problem.
... and that should be safe for tribool. Sure, I'll make that a bool conversion instead of a safe_bool.
The definitions of the comparison operators are not optimal and the generated code is really bad. Something like this would be a lot more efficient (at least with GCC but there is no reason the other compilers would not benefit from this): [snipcode] This code is 8 asm instructions long. The one in the tribool library (the commented line) produces more than 70 asm instructions. The same is true for !=.
Egads! Will fix.
tribool_io.hpp refers to <boost/utility/noncopyable.hpp> but this header is not here.
Fixed locally.
tribool_io_test.cpp should include <cassert>.
Will use the test lib (my local version already does).
Concerning the tutorial, it should be mentioned the || and && operators are not short-circuiting operators contrarily to the boolean versions. I think it is important because it is a limitation of the implementation / language, not an inherent property of tribool.
Ah, good point.
There is a problem with this example: assert(!(y == y)); // okay, because y == y is indeterminate Since y == y is indeterminate, !(y == y) is too, and consequently assert should not be okay, should it?
Oops! Fixed.
And just before, there is this comment: // neither x nor y is false, but we don't know that both are true Shouldn't it be "neither x nor y is false and we know they are not both true"?
I think the original comment is better. Since one or both of the variables is "indeterminate", we don't know if they are true. The comment is addressing the truth of the underlying properties of "x" and "y".
The next comment also need to be modified.
How so? The "or both" was redundant, so I've eliminated it. Doug

"Thomas Witt" <witt@acm.org> wrote in message news:c8g56a$hsh$1@sea.gmane.org...
The review of Douglas Gregor's Tribool library begins now and runs through Saturday, May 29.
Here is my review: I vote for acceptance, with or without the changes I will suggest. I am fairly knowledgable about the problem domain, and spent about an hour reading the documentation, looking at the source and experimenting with the library a bit on VC7.1. The only problem I encountered has already been pointed out (boost/utility/noncopyable.hpp) I think the library is elegantly designed and fills and important need. In the rest of this review I will discuss a possible generalization of the library. ------------------------------------------------------------------- There are a number of different 3-valued logics which have been considered in the theoretical literature. The proposed library implements Kleene's 'strong' 3-valued logic, in which the third value represents an unknown value. There is also Kleene's 'weak' 3-valued logic, in which applying any boolean operation to a set of arguments which contains the third value results in the third value. Other 3-valued logics have been introduced for various purposes. And of course, as others mentioned, there are interesting boolean logics with more than three values. So it seems natural to make tribool a template -- I suggest calling it 'boolean' . Here is a possible synopsis: namespace boost { namespace logic { template<typename TT> // 'truth-table' class boolean { public: .... private: // Make the boolean operations friends int value_; }; // boolean operations ... // Used to declare a named value: #define BOOST_BOOLEAN_VALUE(tt, name, val) ... struct kleene_strong; // Models 'Truth Table' struct kleene_weak; // Models 'Truth Table' typedef boolean<kleene_strong> tribool; typedef boolean<kleene_weak> weak_tribool; // Declare named values 'indeterminate' (for strong 3-valued logic) // and 'undefined' (for weak 3-valued logic) BOOST_BOOLEAN_VALUE(kleene_strong, indeterminate, ...); BOOST_BOOLEAN_VALUE(kleene_weak, undefined, ...); } } // namespace A typical truth table type could look like this: struct kleene_strong { static const int size = 3; // Number of truth-values static int and_(int, int); static int or_(int, int); static int not_(int); static bool true_(int); // Conversion to bool static int eq_(int, int); // operator== }; Here boolean values are represented as ints, with 0 representing false and 1 representing true. I have attached a sample implementation. I wrote it quickly, so it may contain some howlers. I hope the main ideas are clear. Best Regards, Jonathan begin 666 boolean.hpp M+R\@*$,I($-O<'ER:6=H="!*;VYA=&AA;B!4=7)K86YI<R R,# T+@T*+R\@ M4&5R;6ES<VEO;B!T;R!C;W!Y+"!U<V4L(&UO9&EF>2P@<V5L;"!A;F0@9&ES M=')I8G5T92!T:&ES('-O9G1W87)E#0HO+R!I<R!G<F%N=&5D('!R;W9I9&5D M('1H:7,@8V]P>7)I9VAT(&YO=&EC92!A<'!E87)S(&EN(&%L;"!C;W!I97,N M(%1H:7,-"B\O('-O9G1W87)E(&ES('!R;W9I9&5D(")A<R!I<R(@=VET:&]U M="!E>'!R97-S(&]R(&EM<&QI960@=V%R<F%N='DL(&%N9 T*+R\@=VET:"!N M;R!C;&%I;2!A<R!T;R!I=',@<W5I=&%B:6QI='D@9F]R(&%N>2!P=7)P;W-E M+@T*#0HC:69N9&5F($)/3U-47TQ/1TE#7T)/3TQ%04Y?2%!07TE.0TQ51$5$ M#0HC9&5F:6YE($)/3U-47TQ/1TE#7T)/3TQ%04Y?2%!07TE.0TQ51$5$#0H- M"B\O#0HO+R!'96YE<F%L:7IA=&EO;B!O9B!$;W5G;&%S($=R96=O<B=S(%1R M:6)O;VP@;&EB<F%R>2P@;6EN=7,@:2]O+@T*+R\@#0HO+R!.;W1E<SH@#0HO M+R @,2X@26YS=&5A9"!O9B!R97!R97-E;G1I;F<@=&AE(&EN9&5T97)M:6YA M=&4@:V5Y=V]R9',@87,@9G5N8W1I;VYS+ T*+R\@(" @("!)(&UA9&4@=&AE M;2!C;VYS=&%N=',L(&%N9"!A9&1E9"!A9&1I=&EO;F%L(&9U;F-T:6]N<R!I M<U]X>'@-"B\O(" @(" @=&\@=&5S="!B;V]L96%N('9A;'5E(&9O<B!E<75A M;&ET>2!W:71H(&%N(&EN9&5T97)M:6YA=&4N(%1H:7,-"B\O(" @(" @:7,@ M8F5C875S92!)(')A;B!I;G1O('1R;W5B;&4@=VET:"!T:&4@:6UP;&5M96YT M871I;VX@86YD(&1I9&XG= T*+R\@(" @("!H879E('1I;64@=&\@9FEX(&ET M+B Z* T*+R\@(#(N($D@=W)O=&4@=&AI<R!Q=6EC:VQY+"!A;F0@:&%V96XG M="!T97-T960@:70@;75C:"!S;R!I="!M87D@8V]N=&%I;B -"B\O(" @(" @ M<V]M92!H;W=L97)S+B [+2D-"B\O#0H-"@T*(VEN8VQU9&4@/&)O;W-T+V-O M;F9I9RYH<' ^(" @+R\@0D]/4U1?4U1!5$E#7T-/3E-404Y4+"!"3T]35%]* M3TE.#0H-"FYA;65S<&%C92!B;V]S="![(&YA;65S<&%C92!L;V=I8R![#0H- M"B\O#0HO+R!#;&%S<R!N86UE.B!B;V]L96%N#0HO+R!$97-C<FEP=&EO;CH@ M<F5P<F5S96YT<R!A(&=E;F5R86QI>F5D(&)O;VQE86X@='EP90T*+R\@5&5M M<&QA=&4@<&%R86UE=&5R<SH-"B\O(" @(%14("T@<VAO=6QD(&AA=F4@=&AE M(&9O<FTZ#0HO+PT*+R\@(" @("!S=')U8W0@='0@>PT*+R\@(" @(" @(" @ M<W1A=&EC(&-O;G-T(&EN="!S:7IE(#T@,SL@("\O($YU;6)E<B!O9B!T<G5T M:"UV86QU97,-"B\O(" @(" @(" @('-T871I8R!I;G0@86YD7RAI;G0L(&EN M="D[(" -"B\O(" @(" @(" @('-T871I8R!I;G0@;W)?*&EN="P@:6YT*3L- M"B\O(" @(" @(" @('-T871I8R!I;G0@;F]T7RAI;G0I.PT*+R\@(" @(" @ M(" @<W1A=&EC(&)O;VP@=')U95\H:6YT*3L@+R\@0V]N=F5R<VEO;B!T;R!B M;V]L#0HO+R @(" @(" @("!S=&%T:6,@:6YT(&5Q7RAI;G0L(&EN="D[(" @ M+R\@;W!E<F%T;W(]/0T*+R\@(" @("!].PT*+R\@($)O;VQE86X@=F%L=65S M(&%R92!R97!R97-E;G1E9"!A<R!I;G1S+"!W:71H(# @<F5P<F5S96YT:6YG M(&9A;'-E#0HO+R @86YD(#$@<F5P<F5S96YT:6YG('1R=64N#0HO+PT*=&5M M<&QA=&4\='EP96YA;64@5%0^( T*8VQA<W,@8F]O;&5A;B![#0IP<FEV871E M.@T*(" @('-T<G5C="!S869E7V)O;VQ?:&5L<&5R('L@:6YT('@[('T[#0H@ M(" @='EP961E9B!I;G0@<V%F95]B;V]L7VAE;'!E<CHZ*B!S869E7V)O;VP[ M#0IP=6)L:6,Z#0H@(" @8F]O;&5A;B@I(#H@=F%L=65?*# I('L@?0T*(" @ M(&)O;VQE86XH8F]O;"!B*2 Z('9A;'5E7RAB*2![('T-"B @("!O<&5R871O M<B!S869E7V)O;VPH*2!C;VYS=" -"B @("![(')E='5R;B!45#HZ=')U95\H M=F%L=65?*2 _("9S869E7V)O;VQ?:&5L<&5R.CIX(#H@,#L@?0T*+R]P<FEV M871E.B!S:&]U;&0@9W)A;G0@9G)I96YD<VAI<"!T;R!A;&P@=&AE(&]P97)A M=&EO;G,-"B @("!B;V]L96%N*&EN="!V86QU92P@:6YT("\J9'5M;7DJ+RD@ M.B!V86QU95\H=F%L=64I('L@?0T*(" @(&EN="!V86QU95\[#0I].PT*#0IN M86UE<W!A8V4@9&5T86EL('L-"@T*+R\@1F]R(&1E9FEN:6YG(&YA;65D(&-O M;G-T86YT<RX-"G1E;7!L871E/'1Y<&5N86UE(%14+"!I;G0@3CX@#0IS=')U M8W0@8F]O;&5A;E]V86QU92 Z(&)O;VQE86X\5%0^('L-"B @("!B;V]L96%N M7W9A;'5E*"D@.B!B;V]L96%N/%14/BA.+" P*2![('T-"GT[#0H-"GT@(" @ M(" @(" @(" @(" @(" @+R\@16YD(&YA;65S<&%C92!D971A:6PN#0H-"G1E M;7!L871E/'1Y<&5N86UE(%14/@T*8F]O;&5A;CQ45#X@;W!E<F%T;W(A*&)O M;VQE86X\5%0^('@I#0I[(')E='5R;B!B;V]L96%N/%14/BA45#HZ;F]T7RAX M+G9A;'5E7RDL(# I.R!]#0H-"G1E;7!L871E/'1Y<&5N86UE(%14/@T*8F]O M;&5A;CQ45#X@;W!E<F%T;W(F)BAB;V]L96%N/%14/B!X+"!B;V]L96%N/%14 M/B!Y*0T*>R!R971U<FX@8F]O;&5A;CQ45#XH5%0Z.F%N9%\H>"YV86QU95\L M('DN=F%L=65?*2P@,"D[('T-"@T*=&5M<&QA=&4\='EP96YA;64@5%0^#0IB M;V]L96%N/%14/B!O<&5R871O<B8F*&)O;VQE86X\5%0^('@L(&)O;VP@>2D- M"GL@<F5T=7)N(&)O;VQE86X\5%0^*%14.CIA;F1?*'@N=F%L=65?+"!Y*2P@ M,"D[('T-"@T*=&5M<&QA=&4\='EP96YA;64@5%0^#0IB;V]L96%N/%14/B!O M<&5R871O<B8F*&)O;VP@>"P@8F]O;&5A;CQ45#X@>2D-"GL@<F5T=7)N(&)O M;VQE86X\5%0^*%14.CIA;F1?*'@L('DN=F%L=65?*2P@,"D[('T-"@T*=&5M M<&QA=&4\='EP96YA;64@5%0^#0IB;V]L96%N/%14/B!O<&5R871O<GQ\*&)O M;VQE86X\5%0^('@L(&)O;VQE86X\5%0^('DI#0I[(')E='5R;B!B;V]L96%N M/%14/BA45#HZ;W)?*'@N=F%L=65?+"!Y+G9A;'5E7RDL(# I.R!]#0H-"G1E M;7!L871E/'1Y<&5N86UE(%14/@T*8F]O;&5A;CQ45#X@;W!E<F%T;W)\?"AB M;V]L96%N/%14/B!X+"!B;V]L('DI#0I[(')E='5R;B!B;V]L96%N/%14/BA4 M5#HZ;W)?*'@N=F%L=65?+"!Y*2P@,"D[('T-"@T*=&5M<&QA=&4\='EP96YA M;64@5%0^#0IB;V]L96%N/%14/B!O<&5R871O<GQ\*&)O;VP@>"P@8F]O;&5A M;CQ45#X@>2D-"GL@<F5T=7)N(&)O;VQE86X\5%0^*%14.CIO<E\H>"P@>2YV M86QU95\I+" P*3L@?0T*#0IT96UP;&%T93QT>7!E;F%M92!45#X-"F)O;VQE M86X\5%0^(&]P97)A=&]R/3TH8F]O;&5A;CQ45#X@>"P@8F]O;&5A;CQ45#X@ M>2D-"GL@<F5T=7)N(&)O;VQE86X\5%0^*%14.CIE<5\H>"YV86QU95\L('DN M=F%L=65?*2P@,"D[('T-"@T*=&5M<&QA=&4\='EP96YA;64@5%0^#0IB;V]L M96%N/%14/B!O<&5R871O<CT]*&)O;VQE86X\5%0^('@L(&)O;VP@>2D-"GL@ M<F5T=7)N(&)O;VQE86X\5%0^*%14.CIE<5\H>"YV86QU95\L('DI+" P*3L@ M?0T*#0IT96UP;&%T93QT>7!E;F%M92!45#X-"F)O;VQE86X\5%0^(&]P97)A M=&]R/3TH8F]O;"!X+"!B;V]L96%N/%14/B!Y*0T*>R!R971U<FX@8F]O;&5A M;CQ45#XH5%0Z.F5Q7RAX+"!Y+G9A;'5E7RDL(# I.R!]#0H-"G1E;7!L871E M/'1Y<&5N86UE(%14/@T*8F]O;&5A;CQ45#X@;W!E<F%T;W(A/2AB;V]L96%N M/%14/B!X+"!B;V]L96%N/%14/B!Y*0T*>R!R971U<FX@8F]O;&5A;CQ45#XH M5%0Z.FYO=%\H5%0Z.F5Q7RAX+G9A;'5E7RP@>2YV86QU95\I*2P@,"D[('T- M"@T*=&5M<&QA=&4\='EP96YA;64@5%0^#0IB;V]L96%N/%14/B!O<&5R871O M<B$]*&)O;VQE86X\5%0^('@L(&)O;VP@>2D-"GL@<F5T=7)N(&)O;VQE86X\ M5%0^*%14.CIN;W1?*%14.CIE<5\H>"YV86QU95\L('DI*2P@,"D[('T-"@T* M=&5M<&QA=&4\='EP96YA;64@5%0^#0IB;V]L96%N/%14/B!O<&5R871O<B$] M*&)O;VP@>"P@8F]O;&5A;CQ45#X@>2D-"GL@<F5T=7)N(&)O;VQE86X\5%0^ M*%14.CIN;W1?*%14.CIE<5\H>"P@>2YV86QU95\I*2P@,"D[('T-"@T*(V1E M9FEN92!"3T]35%]"3T],14%.7U9!3%5%*'1T+"!N86UE+"!V86PI(" @(" @ M(" @(" @(" @(" @(" @7 T*(" @(&-O;G-T(#HZ8F]O<W0Z.FQO9VEC.CID M971A:6PZ.F)O;VQE86Y?=F%L=64\='0L('9A;#X@;F%M93L@7 T*(" @(&)O M;VP@0D]/4U1?2D])3BAI<U\L(&YA;64I("@Z.F)O;W-T.CIL;V=I8SHZ8F]O M;&5A;CQT=#X@>"D@7 T*(" @('L@<F5T=7)N('@N=F%L=65?(#T]('9A;#L@ M?2 @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @7 T*(" @("\J*B\@ M(" @+R\@5FEO;&%T97,@96YC87!S=6QA=&EO;B M+2!A;GD@<W5G9V5S=&EO M;G,_#0H-"G-T<G5C="!K;&5E;F5?<W1R;VYG('L-"B @("!"3T]35%]35$%4 M24-?0T].4U1!3E0H:6YT+"!S:7IE(#T@,RD[#0H@(" @<W1A=&EC(&EN="!A M;F1?*&EN="!X+"!I;G0@>2D-"B @(" @(" @>PT*(" @(" @(" @(" @:68@ M*'@@/3T@,"!\?"!Y(#T](# I( T*(" @(" @(" @(" @(" @(')E='5R;B P M.PT*(" @(" @(" @(" @96QS92!I9B H>" ]/2 Q("8F('D@/3T@,2D@#0H@ M(" @(" @(" @(" @(" @<F5T=7)N(#$[#0H@(" @(" @(" @("!E;'-E#0H@ M(" @(" @(" @(" @(" @<F5T=7)N(#([#0H@(" @(" @('T-"B @("!S=&%T M:6,@:6YT(&]R7RAI;G0@>"P@:6YT('DI#0H@(" @(" @('L-"B @(" @(" @ M(" @(&EF("AX(#T](#$@?'P@>2 ]/2 Q*2 -"B @(" @(" @(" @(" @("!R M971U<FX@,3L-"B @(" @(" @(" @(&5L<V4@:68@*'@@/3T@," F)B!Y(#T] M(# I( T*(" @(" @(" @(" @(" @(')E='5R;B P.PT*(" @(" @(" @(" @ M96QS90T*(" @(" @(" @(" @(" @(')E='5R;B R.PT*(" @(" @("!]#0H@ M(" @<W1A=&EC(&EN="!N;W1?*&EN="!X*0T*(" @(" @("![#0H@(" @(" @ M(" @("!R971U<FX@>" ]/2 Q(#\@," Z('@@/3T@," _(#$@.B R.PT*(" @ M(" @("!]#0H@(" @<W1A=&EC(&)O;VP@=')U95\H:6YT('@I('L@<F5T=7)N M('@@/3T@,3L@?0T*(" @('-T871I8R!I;G0@97%?*&EN="!X+"!I;G0@>2D- M"B @("![(')E='5R;B H>" ]/2 R('Q\('D@/3T@,BD@/R R(#H@>" ]/2!Y M.R!]#0I].PT*#0IS=')U8W0@:VQE96YE7W=E86L@>PT*(" @($)/3U-47U-4 M051)0U]#3TY35$%.5"AI;G0L('-I>F4@/2 S*3L-"B @("!S=&%T:6,@:6YT M(&%N9%\H:6YT('@L(&EN="!Y*0T*(" @(" @("E='5R;B H>" ]/2 R('Q\('D@/3T@,BD@/PT*(" @(" @(" @ M(" @(" @(#(@.@T*(" @(" @(" @(" @(" @('@@?'P@>3L-"B @(" @(" @ M?0T*(" @('-T871I8R!I;G0@;F]T7RAI;G0@>"D@>R!R971U<FX@('@@/3T@ M,B _(#(@.B A>#L@?0T*(" @('-T871I8R!B;V]L('1R=65?*&EN="!X*2N('@@/3T@>3L@?0T*?3L-"@T*='EP961E9B!B;V]L M96%N/&ML965N95]S=')O;F<^("!T<FEB;V]L.PT*='EP961E9B!B;V]L96%N M/&ML965N95]W96%K/B @("!W96%K7W1R:6)O;VP[#0H-"D)/3U-47T)/3TQ% M04Y?5D%,544H:VQE96YE7W-T<F]N9RP@:6YD971E<FUI;F%T92P@,BD-"D)/ M3U-47T)/3TQ%04Y?5D%,544H:VQE96YE7W=E86LL('5N9&5F:6YE9"P@,BD- M"B @(" @(" @(" -"GT@?2 @(" @(" @(" @(" @(" @+R\@16YD(&YA;65S M<&%C97,@;&]G:6,L(&)O;W-T+@T*#0HC96YD:68@+R\@(VEF;F1E9B!"3T]3
5%],3T=)0U]"3T],14%.7TA04%])3D-,541%1 T* ` end
participants (6)
-
Doug Gregor
-
Douglas Gregor
-
Guillaume Melquiond
-
Jonathan Turkanis
-
Pavel Vozenilek
-
Thomas Witt