Demo: Quick Lambdas, Looping Polymorph Solver

แชร์
ฝัง
  • เผยแพร่เมื่อ 26 ส.ค. 2024

ความคิดเห็น • 62

  • @EvanTeran
    @EvanTeran 8 ปีที่แล้ว +7

    Regarding the generic lambdas, nicely done. For everyone's reference, you can achieve same level of generic-ness with C++14's generic lambdas. For example:
    // could make return type "-> decltype(x.name)", but not necessary
    auto get_name = [](auto x) {
    return x.name;
    };
    std::cout

  • @EvanTeran
    @EvanTeran 8 ปีที่แล้ว +4

    The reason why your first c++ template example doesn't work is because you try to do a decltype on x before x exists. This is resolved using the new function syntax like this:
    template
    auto poly_incr(T x) -> decltype(x + 1) { return x + 1; }
    Which is interestingly enough, similar to your function return syntax...
    As you discovered though, you can just leave out the return type for simple cases.

  • @MaherBaba
    @MaherBaba 8 ปีที่แล้ว +2

    Excellent work Mr. Blow

  • @EivindDahl
    @EivindDahl 7 ปีที่แล้ว +4

    I'm really looking forward to playing around with this language.

  • @walter0bz
    @walter0bz 7 ปีที่แล้ว +2

    45:30 "i don't know why it's not done in C++" - what I've learned in the Rust community is it's tied to how overloading (or lack of) works. Rust has the more advanced inference but bounded polymorphism. C++ needs to know the types to pick overloads. as such C++ can't quite infer forwards so much and keep things consistent with previous assumptions about how overloading works.

  • @angeldude101
    @angeldude101 8 ปีที่แล้ว +2

    You mentioned the scripting languages are popular due to not having to care about writing the type everywhere. That got me thinking about the custom allocators and compile-time execution. It should be possible for someone to write a custom allocator that can handle garbage collection, combine that with the fact that the compiler is also an interpreter and you just acidently made a scripting language on the same level as Python and Javascript, with optional compilation on the level of C and C++.

    • @andreffrosa
      @andreffrosa หลายเดือนก่อน

      For that to work, the compiler would still need to do and add some features to enable the garbage collector to know when it can run and collect a given pointer. That is, it would have to do inject some automatic reference counting or a similar mechanism.

  • @movax20h
    @movax20h 8 ปีที่แล้ว +8

    Comparing any language to ancient C++ with even all the recent additions is unfair.
    All of that is supported for years in D. (In fact a lot of stuff in C++11 and C++14 is borrowed from D).
    auto names = map(guys, x => x.name);
    just like that. D map is extremely polymorphic, and can be both implemented to do streaming / pipeing, or return actually array of results (with additional allocation). The ranges used in D, knows the size of container so no need to pass size. And yes map will know how to deduce the types in this case.
    Even in C++ you do not need to pass this crazy long type example with unordered_map, you can just use poly_incr. But I agree, C++ is limited.
    Simple implementation of map in D:
    auto map(T)(T[] m, delegate R f(T)) {
    R[] r;
    foreach (x; m) {
    r ~= f(x);
    }
    return r;
    }
    If you want to name the function you can do it like this:
    auto get_name(T)(T x) {
    return x.name;
    }
    (you do not even need to put keyword template here).
    It will infer the return type automatically.
    Sorting:
    sort!"a.name > b.name"(guys);
    sort!"compare_strings(b.name, a.name)"(guys);
    easy.
    Check dlang.org/phobos/std_algorithm_iteration.html#.map
    alias stringize = map!(to!string);
    is for exaple nice. stringize is a mapper from ANY type that the to!string can be called on. to!string is a template function. a stringize become a template function too. or kind of free function without types assigned (with exact type to be determined later at the call site).
    For the nightmear example with passed other templates, I have no idea if it will work in D. probably.
    For the infix part, D automatically will extend all types with method with one less parameter acting on the first parameter of this type.
    i.e.
    you can do map(guys, x => x.name).
    but you can also do
    guys.map(x => x.name).
    This is nice for chaining,
    guys.map(x => x.name).map(uppercase);
    is nicer than
    map!uppercase(map(guys, x => x.name)),
    because it is kind of a mess.
    guys.sort!"a.health > b.health"().each!(x => writefln(x.name, x.health))();
    I am sure, there are some tricks to make it shorter. I.e. make sort accept a function to a key, not actual comparison function.

    • @nickeshchauhan5661
      @nickeshchauhan5661 7 ปีที่แล้ว +7

      Keep in mind this is a language designed for game programming, which for large-scale development is very highly skewed in favour of C++.
      Therefore it makes sense to compare the features and pitfalls against C++.

    • @jblow888
      @jblow888  7 ปีที่แล้ว +9

      Indeed, C++ is the game industry standard and there is a reason for that.
      I think D has a lot of good ideas, language-wise, but honestly the D community is kind of annoying, in that someone or another is always coming by to tell me why I am stupid for not just using D. People from the Rust and Go communities don't do that...

  • @walter0bz
    @walter0bz 7 ปีที่แล้ว +1

    27:32 this sort of thing is a little less painful in c++ now passing vectors around and relying on r-value references to move the return result. you can even use 'template-template parameters' to parameterise over the collection type. you can also pass a callable object template ... F f... f(src).., or std::function. It can certainly handle the 'map' example
    Rust is noticeably better at this sort of thing though, with more complex inference

  • @EvanTeran
    @EvanTeran 8 ปีที่แล้ว +2

    Also, one last thing, you CAN (in c++14) do things like your poly_incr with templates. The reason why it didn't work in your example is because you made map take a function pointer, which means that it needs a very specific match forcing you to give type hints as you noted.
    If you make that more generic and allow ANY callable thing, you can pass a generic lambda, a function pointer, etc... and it works just fine: ideone.com/WiXPqF

    • @jblow888
      @jblow888  8 ปีที่แล้ว

      Okay, but that's ... very counterintuitive and weird, at least? In order to make it work I have to get *less* specific about what I am doing, not more specific? (The error messages are definitely going to be worse...)

    • @EvanTeran
      @EvanTeran 8 ปีที่แล้ว +2

      +Jonathan Blow yea, it's true that having your callback parameter as a template itself so that any callable thing can be passed is learned and not intuited. once you get used to it, it works decently though.
      you could use std::function, but at a runtime cost, so I avoid that as much as I can.
      And for sure, until we get concepts, template error messages are a nightmare!

  • @espadrine
    @espadrine 8 ปีที่แล้ว +1

    Your type resolution algorithm is essentially Hindley-Milner inference. The reason C++ doesn't do this is partly that it tends to slow compilation in a language that supports both mutability, subclassing and function overloading. Languages like Swift and Scala do this nonetheless, and they can have critically slow compilation. Languages like Rust and Go limit it by requiring certain type annotations; typically function parameters. Languages like Haskell and OCaml keep fast compilation while having all type annotations optional by having a fancy polymorphic type system. (OCaml is truly underrated, but to be fair, its syntax is not the best.)

    • @jblow888
      @jblow888  8 ปีที่แล้ว +1

      No, it's not Hindley-Milner, because it's constrained in terms of where it gets information from and where it applies it to.
      And no, the reason C++ doesn't do it has nothing to do with compilation speed. (In fact it's very fast if applied in the way I am doing it).

    • @espadrine
      @espadrine 8 ปีที่แล้ว

      Hindley-Milner inference implementations also have those constraints in practice.
      The way you are doing it is fast because of the restriction of the currently supported feature set. Add in subtyping, function overloading and literal genericity (ie, 1 is a uint32 or a sint32 or…), and inference becomes heavier. Let alone type conversion, which Scala has - Scala is famous for its compilation times.
      C++ has subtyping and overloading, which slows down this approach. Your going with that approach either means you will never have those features, or you will be OK with potentially slow compilation times, as Swift and Scala are. My understanding is that you favour the former.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +4

      Thaddee Tyl We already have all the features you're talking about, and compilation speed is reasonably fast already, and we have done almost nothing to optimize the compiler yet (name lookups are just linear array searches, including in the global namespace!) Right now for a 20k-line program, the amount of time spent in the front-end is 0.6 seconds -- and again, that is completely unoptimized (I am going to do some work this weekend to get that number down).
      The reason we are fast is because the design of the language does not permit much in the way of combinatorics in the way these features interact. Yes, 1 can be signed or unsigned or of any size, but we don't make a big deal out of that; the way we handle it is very lightweight. We don't get into the kind of solver-with-backtracking situation that e.g. Swift has.
      As for whether you want to call the inference we are doing Hindley-Milner or not, whatever. I am not of the opinion that what we are doing is a complex or new enough idea to have its own name. If you are going to say that's Hindley-Milner then fine, but then I'll say why does Hindley-Milner have its own name if it is such a simple and obvious idea?

    • @jblow888
      @jblow888  8 ปีที่แล้ว +4

      (I should also comment that most of that 0.6 seconds is being spent on language features that most of these other languages do not even do, like support for program manipulation via compile-time code execution.)

  • @hasen1957
    @hasen1957 6 ปีที่แล้ว +1

    This was a great demonstration, IMO, of things that are not impossible to do, and yet a lot of "experts" in the industry couldn't think of coming up with.
    I wonder why.
    I have a feeling it might be due to the FUD campaign that has been going on against procedural programming with for loops and if statements. "looping" manually is evil! you must use maps and filters and reduce! As a result people are "forgetting" how to do things.
    From what I have heard, the Swift compiler is slow specifically because of type inference. Apparently you have to specify as much type information as possible upfront so the compiler doesn't have to spend time figuring out the types of everything.
    Some times, compiling small files can take several seconds, not for optimization or anything; just for type inference.

  • @MaherBaba
    @MaherBaba 8 ปีที่แล้ว +5

    I bet the chat was slaying him when he tried to use decltype() as return type

    • @jblow888
      @jblow888  8 ปีที่แล้ว +7

      Well, it was the straightforward translation of the code in my language, so it was the first thing I typed. I am not sure whether it makes sense or not, since I have no idea how template stuff really works in C++ ... it is just too crazy complicated to bother with. That said, I am guessing the reason it doesn't work is that in C++ 'x' is not in scope until you get into the procedure body, but SFINAE was causing it not to generate an error when there was another template of the same name. Or some garbage like that.

    • @MaherBaba
      @MaherBaba 8 ปีที่แล้ว +10

      Jonathan Blow
      I didn't mean to insult you, but I know what internet chats are like. You would be correct, the solution is to write (...) -> decltype(x.foo), exactly like with your type_of()
      , have a good day sir

    • @MaherBaba
      @MaherBaba 8 ปีที่แล้ว +4

      Jonathan Blow
      oh and you would have to use auto for the "normal" return type

    • @Phoenix555315
      @Phoenix555315 8 ปีที่แล้ว +4

      +Jonathan Blow x isn't visible because it parses left to right, that's why you need a trailing return type instead there

  • @ihrbekommtmeinenrichtigennamen
    @ihrbekommtmeinenrichtigennamen 8 ปีที่แล้ว +1

    The "solver" you explained is very similar to C#'s type inference algorithm:
    ericlippert.com/2012/10/02/how-do-we-ensure-that-method-type-inference-terminates/
    In every iteration it has to "fix" (the C# term for finding the actual type which is used in place of a generic type) at least one generic type. If it does not make any progress in an iteration it stops.

  • @dcy665
    @dcy665 8 ปีที่แล้ว +1

    Compiler people are not looking at the actual compiler. They are looking at the language definition and there is little if any focus on making a useful product. They don't have to, they are locked into the path forward and there is little that we can do about it. Except supporting you and a better language, with a better solution.
    Read Linus and his reactions to gcc folks.
    2014: lkml.iu.edu//hypermail/linux/kernel/1407.3/00650.html
    2015: lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html
    In my experience is the gcc team is better than the MSFT one. Ouch.

  • @FalconGames109
    @FalconGames109 8 ปีที่แล้ว +3

    Nice, just got the same kind of polymorphism solving working in my own language :)
    I wonder how your compiler would support Rank-N Polymorphism:
    f :: (g: ($T) -> T) -> (T, T) {
    return (g(1), g("hi"));
    }
    id :: (x: $T) -> T {
    return x;
    }
    f(id);
    Since your type inference is starting to look more and more like HM-style global type inference, I'm not sure how this would work out.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +7

      This example would not work, by design. My goal is not to build a type inference system whose job it is to put together whatever scant information may be available anywhere in the program in order to come up with a solution. When the solver has to do this, I think we're in a situation where the programmer doesn't really know what's going on; and also, when languages are based around solvers like this, compilation speed really suffers. My goal is for compilation to be very fast and for programmers to always understand what is really happening.

    • @gcewing
      @gcewing ปีที่แล้ว

      Seems to me that shouldn't work as written in any case. It's saying that f returns two things of the same type, but g(1) and g("hi") return different types.
      There's also the issue of the scoping of the type variables. Is T a type variable of f, or is it a type variable of g? There seems to be an ambiguity here, and I'm not sure which way Jai would interpret it, or how you would force the other interpretation if you wanted it.
      In C++ and C# this kind of ambiguity doesn't arise, because you always explicitly introduce new type variables, eg. T id (T x) {return x;}, and this makes it clear what their scope is.

  • @joaoedu1917
    @joaoedu1917 8 ปีที่แล้ว

    the aesthetics/idiom is looking a lot like Go. which is great.

    • @joaoedu1917
      @joaoedu1917 8 ปีที่แล้ว

      oh, now combined with some pythonlike nimbleness.

  • @walter0bz
    @walter0bz 7 ปีที่แล้ว +1

    51:30 "almost like dot calls..."... just do UFCS... :) or maybe something like F# 's |> operator?

  • @anycomb814
    @anycomb814 5 ปีที่แล้ว

    The C++ excursion makes this demo look bad. Most of what you think cannot be done is actually quite straightforward with lambda syntax. The map function could be implemented with much less boilerplate and hassle.
    This project looks promising either way, keep it up.

  • @AsmageddonPrince
    @AsmageddonPrince 8 ปีที่แล้ว +1

    Three things I noticed:
    1) I think it'd be better if pointers were non-nullable by default
    2)It'd probably be more clear if you had for-in, with explicitly named iteration variable(s - it would work with multiple iteration variables better, too)
    3) Skipping {}s with for isn't much of a saving in terms of characters, it's just a way to sometimes introduce hard-to-spot bugs.
    Anyway, great stuff :)

    • @jblow888
      @jblow888  8 ปีที่แล้ว +2

      (1) I think most serious low-level game programmers would disagree.
      (2) You can have explicitly-named iteration variables.

    • @AsmageddonPrince
      @AsmageddonPrince 8 ปีที่แล้ว +1

      I don't think so, you can easily have nullable-pointer syntax with ?, preferably as syntactic sugar to a Maybe/Option wrapper, but most pointers usually shouldn't be null, and having the type system check that for you is usually a great thing.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +3

      Arek Stefański No, it's really not that easy. One large problem is that if you create a struct, it won't have initialized pointers. So either *every* struct has to contain Maybe pointers by default, which is going to introduce a huge amount of friction, or else you have to introduce some kind of heavy-handed constructor situation, wherein you have to say when you are initializing things and how. Maybe this latter solution could be good and cut down on errors overall, if it is lightweight and there are more checks that can be usefully done than just null pointers. But it's a relatively difficult problem that deserves a lot of thought.

    • @AsmageddonPrince
      @AsmageddonPrince 8 ปีที่แล้ว

      I don't think it's heavy handed - you can easily track the fields of an object in a context where you allocate it, and throwing an error when trying to access an uninitialized non-nullable field, or return an incomplete object is relatively simple, and it's something that is already a trend among newer PLs.
      Well, a more complex part of this is that it changes how you treat things a bit, since now each step of a . chain returns a Maybe - although null-safe access operators and being able to specify a default, e.g. Java's `int x = obj?.pos?.x ?: -1` make it manageable. I guess you're right that it's a difficult problem. Implementation details aside, it's probably gonna have an impact on how the code is written. And it'd mean having to introduce typed unions and some pattern matching on them to make them pleasant to use, which is a nice thing to have, but again, ends up causing more changes in how the code is written. I don't really have the pragmatism it takes to make a C-like language, I guess. x.x
      Well, whether you go with it or not, I think that null-safe and null-default operators would be a nice thing to have, anyway. I probably should have thought of them before non-nullability to be fair. u.u

  • @rudolfwg
    @rudolfwg 8 ปีที่แล้ว +2

    Weaving some code, eh? Typos ftw! :D (en.wikipedia.org/wiki/Lamba)
    Edit: to preempt bafflement from posterity: the title originally read "quick lambas", and lambas are a kind of woven cloth, hence my pun.

  • @freiherrvonundzu
    @freiherrvonundzu 8 ปีที่แล้ว +1

    +Jonathan Blow your C++ example is incorrect. The declaration of the type of the result array should be using R instead of T.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +3

      I think you mean this line?
      auto result = new T[array_len];
      Yes, that is a mistake! Fortunately in the example, T and R are the same anyway, so it did not cause a problem.

    • @freiherrvonundzu
      @freiherrvonundzu 8 ปีที่แล้ว +1

      yes, exactly. just fyi in case you wanted to build your next demo upon this c++ example

  • @DrDiablo36
    @DrDiablo36 8 ปีที่แล้ว

    This was such a fun video to watch, on many levels. Thanks for taking the time to share.
    Just two random ideas: a cool syntax stolen from clojure to have a function to access properties, like `(x) => x.name` (quietly wishing youtube supported markdown), would be `.name` which would literally just desugar into your
    ```
    get_name :: (x: $T) -> type_of(T.name) {
    return x.name;
    }
    ```
    Mapping would look like `map(arr, .name)`
    That said, too much sugar makes you fat :p
    Another idea was for named operators you could use `~name`
    So: `vec1 ~cross vec2 ~cross vec3`

  • @shavais33
    @shavais33 4 ปีที่แล้ว

    Javascript:
    const f = x => x.name;
    Jai:
    f :: x => x.name;
    Jai is now more succinct than JavaScript! =D
    (At least as far as that goes.)
    And we don't have objects that carry entire scopes full of multiply-copied, obscure, behind the scenes add-ons that we rarely if ever directly need or use!
    So what does JavaScript have over Jai for people who like dynamically typed languages? Well, I don't think I'm going to place any bets at the moment as I haven't finished watching the demos yet. At this point it looks like JavaScript still has a few things, like native json literrals (succinct unordered_map constructors), async await, function chaining, dynamically adding attributes to existing objects..

  • @Mempo1
    @Mempo1 5 ปีที่แล้ว +2

    compile time function execution? hmm cool *googles how to replicate in c++ to then find out it can't*

    • @sebastianmestre8971
      @sebastianmestre8971 4 ปีที่แล้ว

      Not as powerful as Jai's #run directive, but, C++ has constexpr and consteval, which let you do (somewhat limited, though being extended more and more on each C++ version) compile time execution.

  • @iceX33
    @iceX33 8 ปีที่แล้ว

    Is the API discoverability an issue you are considering, or is currently out of scope?
    The ' notation makes procedure discoverability (IntelliSense) easier. However multi step polymorph solver makes it harder again :)
    The main problem with IntelliSense, or autocomplete if you will, is that it has to work on "broken" code. The IDE has to recover from parse errors and try to create exhaustive model of the program in order to present the user with current possibilities. Multi step polymorph solver makes this much more challenging. Not saying that it is impossible, I guess with partial model reconstruction and a limit on "live" solver iterations this would be feasible.

    • @FalconGames109
      @FalconGames109 8 ปีที่แล้ว

      Check out F#. It has IntelliSense support and a fairly similar type inference algorithm. Similarly, OCaml has a similar type system as well as "row polymorphism", which is essentially the feature with `(x: $T) -> type_of(x.name)` and supports IntelliSense-style suggestions with Merlin (github.com/the-lambda-church/merlin). So unless Jai's type system becomes significantly more complex, it would be possible to keep IntelliSense-style autocomplete (although it might take a lot more work to get it working effectively).

    • @Raattis
      @Raattis 8 ปีที่แล้ว

      In the structs with parameters demo the user generated code ended up in its own temp file for debugging purposes. That or something similar could possibly be leveraged for this too.
      And if everything else fails the compiler can be used as a library to gather information about available functions and their polymorphic parameters.

    • @iceX33
      @iceX33 8 ปีที่แล้ว

      +No Pico (Pls) I am not really familiar with F# to be honest, but from Jai perspective, let's imagine I type foo ' now I have to analyze which procedures can be suggested. We know the type of foo. So we can list all the procedures which have type of foo as first parameter. Now we can also have list of already baked polymorphic functions which take the type of foo as first argument, but to be really precise we have to go over all polymorphic procedures and try to bake them with type of foo. We could blacklist some procedures where we already tried backing with the given type and could not succeed. So yeah probably possible but challenging.

    • @iceX33
      @iceX33 8 ปีที่แล้ว

      +Raattis depends on how high your expectations are to autocomplete and how flexible your compiler is. Normally compilers are written in the way that they find the broken place and point it out. As I mentioned before a system in charge of autocomplete must recover from syntactical errors. A really good one will recover / suggest a solution when you have a semantic errors as well. For example it should be able to suggest you a procedure which is not in scope yet if it can be imported. It should suggest options depending on the context and flow analysis. None of this complex things are really needed as part of a "standard" compiler.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +1

      If you presume that you are using metadata that was generated last time the program was compiled, then if a polymorphic function was ever generated with foo's type as the first argument, then you know that as well, without having to look very hard.

  • @Dengakuman22
    @Dengakuman22 8 ปีที่แล้ว

    Your looping polymorph solver does look a lot like a type inference algorithm to me. In a type inference scenario you could think of all variables being of a polymorphic unknown type and the loop solver would be resolving the constraints on which type is which until everything is decided.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +2

      Sure, that is basically what it is. The difference between this and most type inference systems is that this system is intentionally limited to a narrower context.

  • @krux02
    @krux02 8 ปีที่แล้ว +2

    I think you should have a better understanding of c++ templates, to be able to argue why they are not sufficient. Arguing that something is not able to do something, when in reality you just don't understand is doesn't make you shine in the best light.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +6

      My point was that C++ templates could not do that relatively simple example without type hinting or without the programmer going through weird contortions. Evan T below says the following thing works (I haven't tried it):
      ideone.com/WiXPqF
      Okay, but how as a programmer am I supposed to know to do that that? Isn't that just unreasonable and weird?
      And then once I do that, well, I still haven't solved the original problem .. because I don't get the typechecking on f ... which was the whole point of the original example! So if your claim is that C++ can solve the problem just fine, by ignoring part of the problem, I will just say that doesn't sound like a very reasonable claim to me. (But I can't really tell what you are claiming, because you didn't reply with an actual example that furthers the discussion, you just went ad hominem).
      Defending C++ in cases like this just seems like some kind of weird Stockholm syndrome. It is much better to have a clear picture of what is broken and weird, because then there's a chance at fixing it.

    • @krux02
      @krux02 8 ปีที่แล้ว

      I am sorry if my comment made you feel insulted in any way, that was was not my intention. I forked that example and added the type checking on f. And yes it is very weird. But it is possible. Here is the code
      ideone.com/pvWjPz
      I am not trying to defend c++ here, but I think if you really want to convince people that c++ is bad, I you need to know the ugly parts, and show counterintuitive and obfuscating it is. A part where it might even work better than this would be iterators.
      Iterators are designed to mimic the look and feel of C pointer and pointer arithmetic. So when you define an iterator, you define `++` and `*` operators on them. When you want to have random access iterators, you can also support `+` for pointer and integer. But when you want to write generic code, you should not use the + operator, because you don't know weather it is defined or not, you should use std::next which calls ++ N times when + is not defined. First of all, how are you supposed to know that? And it's pure ugliness, you have to define operators to give you a nicer interface, but then you are not supposed to use them.

    • @jblow888
      @jblow888  8 ปีที่แล้ว +5

      krux02 Well wait, if you are going to go using std::function, you are now very likely inducing a runtime cost, so again it's not the same problem any more. Plus on top of that you have a whole extra layer of indirection. I don't really consider this to be a reasonable solution if convenience for the programmer is at all a consideration.
      About this:
      "but I think if you really want to convince people that c++ is bad, I you need to know the ugly parts, and show counterintuitive and obfuscating it is."
      My target audience already knows C++ is pretty terrible, so it is not my goal to convince anyone of that. If you don't think C++ is terrible, then go on using it, that's fine. Once in a while I use C++ functionality as a reference, as I did in this video, mainly because the practical matter under consideration is the replacement of C++ for the purposes of making high-performance games. But answering the question "what does this do better than C++", for people who already know C++ is bad and want to get off it, is a different thing from convincing people C++ is bad. I am not right now very interested in doing that latter thing, just because I have a lot of programming and design to do. And probably the best demonstration is to give people a compiler that runs very fast, gives them very powerful expressibility, and lets them write shorter programs that have fewer bugs. So that is how I am going to do it.

    • @krux02
      @krux02 8 ปีที่แล้ว +1

      I never did any performance test to compare std::function to something else. But the only performance difference I can think of to actually make a difference, is the virtual dispatch when called. A templated function can normally inline the callback function. But since you used function pointers as pointer type, I assumed it would be equally valid to use std::function. And thanks for you explanation.