Why don't programming languages automatically manage the synchronous/asynchronous problem? The Next CEO of Stack OverflowWhich layer does async code belong?Combining asynchronous and synchronous programmingUse cases and usage patterns of futures vs callbacksLanguage compiled to JS – most elegant way to do synchronous-style waitsSynchronous facade hiding asynchronous web serviceUsing and designing asynchronous APIs with naturally synchronous partsWhy are Promises not “awaited” by default?Design of asynchronous componentWhy do many languages semantically distinguish “async” functions from “non-async” ones?sequential command processing with an async io cloud upsert

free fall ellipse or parabola?

Yu-Gi-Oh cards in Python 3

Why don't programming languages automatically manage the synchronous/asynchronous problem?

How do I fit a non linear curve?

Defamation due to breach of confidentiality

Why is the US ranked as #45 in Press Freedom ratings, despite its extremely permissive free speech laws?

Is fine stranded wire ok for main supply line?

Which one is the true statement?

Raspberry pi 3 B with Ubuntu 18.04 server arm64: what chip

Do I need to write [sic] when including a quotation with a number less than 10 that isn't written out?

Point distance program written without a framework

What would be the main consequences for a country leaving the WTO?

Getting Stale Gas Out of a Gas Tank w/out Dropping the Tank

Reshaping json / reparing json inside shell script (remove trailing comma)

Why did early computer designers eschew integers?

Players Circumventing the limitations of Wish

Why do we say 'Un seul M' and not 'Une seule M' even though M is a "consonne"

Where do students learn to solve polynomial equations these days?

Is it correct to say moon starry nights?

How to Implement Deterministic Encryption Safely in .NET

Lucky Feat: How can "more than one creature spend a luck point to influence the outcome of a roll"?

In the "Harry Potter and the Order of the Phoenix" video game, what potion is used to sabotage Umbridge's speakers?

Calculate the Mean mean of two numbers

TikZ: How to fill area with a special pattern?



Why don't programming languages automatically manage the synchronous/asynchronous problem?



The Next CEO of Stack OverflowWhich layer does async code belong?Combining asynchronous and synchronous programmingUse cases and usage patterns of futures vs callbacksLanguage compiled to JS – most elegant way to do synchronous-style waitsSynchronous facade hiding asynchronous web serviceUsing and designing asynchronous APIs with naturally synchronous partsWhy are Promises not “awaited” by default?Design of asynchronous componentWhy do many languages semantically distinguish “async” functions from “non-async” ones?sequential command processing with an async io cloud upsert










22















I have not found many resources about this: I was wondering if it's possible/a good idea to be able to write asynchronous code in a synchronous way.



For example, here is some JavaScript code which retrieves the number of users stored in a database (an asynchronous operation):



getNbOfUsers(function (nbOfUsers) console.log(nbOfUsers) );


It would be nice to be able to write something like this:



const nbOfUsers = getNbOfUsers();
console.log(getNbOfUsers);


And so the compiler would automatically take care of waiting for the response and then execute console.log. It will always wait for the asynchronous operations to complete before the results have to be used anywhere else. We would make so much less use of callbacks promises, async/await or whatever, and would never have to worry whether the result of an operation is available immediately or not.



Errors would still be manageable (did nbOfUsers get an integer or an error?) using try/catch, or something like optionals like in the Swift language.



Is it possible? It may be a terrible idea/a utopia... I don't know.










share|improve this question









New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 43





    I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

    – Jörg W Mittag
    2 days ago







  • 4





    @JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

    – Caleth
    2 days ago






  • 5





    What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

    – freakish
    2 days ago







  • 5





    Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

    – Bergi
    2 days ago







  • 5





    When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

    – Rob
    2 days ago















22















I have not found many resources about this: I was wondering if it's possible/a good idea to be able to write asynchronous code in a synchronous way.



For example, here is some JavaScript code which retrieves the number of users stored in a database (an asynchronous operation):



getNbOfUsers(function (nbOfUsers) console.log(nbOfUsers) );


It would be nice to be able to write something like this:



const nbOfUsers = getNbOfUsers();
console.log(getNbOfUsers);


And so the compiler would automatically take care of waiting for the response and then execute console.log. It will always wait for the asynchronous operations to complete before the results have to be used anywhere else. We would make so much less use of callbacks promises, async/await or whatever, and would never have to worry whether the result of an operation is available immediately or not.



Errors would still be manageable (did nbOfUsers get an integer or an error?) using try/catch, or something like optionals like in the Swift language.



Is it possible? It may be a terrible idea/a utopia... I don't know.










share|improve this question









New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 43





    I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

    – Jörg W Mittag
    2 days ago







  • 4





    @JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

    – Caleth
    2 days ago






  • 5





    What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

    – freakish
    2 days ago







  • 5





    Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

    – Bergi
    2 days ago







  • 5





    When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

    – Rob
    2 days ago













22












22








22


7






I have not found many resources about this: I was wondering if it's possible/a good idea to be able to write asynchronous code in a synchronous way.



For example, here is some JavaScript code which retrieves the number of users stored in a database (an asynchronous operation):



getNbOfUsers(function (nbOfUsers) console.log(nbOfUsers) );


It would be nice to be able to write something like this:



const nbOfUsers = getNbOfUsers();
console.log(getNbOfUsers);


And so the compiler would automatically take care of waiting for the response and then execute console.log. It will always wait for the asynchronous operations to complete before the results have to be used anywhere else. We would make so much less use of callbacks promises, async/await or whatever, and would never have to worry whether the result of an operation is available immediately or not.



Errors would still be manageable (did nbOfUsers get an integer or an error?) using try/catch, or something like optionals like in the Swift language.



Is it possible? It may be a terrible idea/a utopia... I don't know.










share|improve this question









New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












I have not found many resources about this: I was wondering if it's possible/a good idea to be able to write asynchronous code in a synchronous way.



For example, here is some JavaScript code which retrieves the number of users stored in a database (an asynchronous operation):



getNbOfUsers(function (nbOfUsers) console.log(nbOfUsers) );


It would be nice to be able to write something like this:



const nbOfUsers = getNbOfUsers();
console.log(getNbOfUsers);


And so the compiler would automatically take care of waiting for the response and then execute console.log. It will always wait for the asynchronous operations to complete before the results have to be used anywhere else. We would make so much less use of callbacks promises, async/await or whatever, and would never have to worry whether the result of an operation is available immediately or not.



Errors would still be manageable (did nbOfUsers get an integer or an error?) using try/catch, or something like optionals like in the Swift language.



Is it possible? It may be a terrible idea/a utopia... I don't know.







programming-languages syntax asynchronous-programming






share|improve this question









New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 12 hours ago









Peter Mortensen

1,11521114




1,11521114






New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 2 days ago









CinnCinn

22518




22518




New contributor




Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Cinn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 43





    I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

    – Jörg W Mittag
    2 days ago







  • 4





    @JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

    – Caleth
    2 days ago






  • 5





    What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

    – freakish
    2 days ago







  • 5





    Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

    – Bergi
    2 days ago







  • 5





    When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

    – Rob
    2 days ago












  • 43





    I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

    – Jörg W Mittag
    2 days ago







  • 4





    @JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

    – Caleth
    2 days ago






  • 5





    What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

    – freakish
    2 days ago







  • 5





    Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

    – Bergi
    2 days ago







  • 5





    When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

    – Rob
    2 days ago







43




43





I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

– Jörg W Mittag
2 days ago






I don't really understand your question. If you "always wait for the asynchronous operation", then it is not an asynchronous operation, it is a synchronous operation. Can you clarify? Maybe give a specification of the type of behavior you are looking for? Also, "what do you think about it" is off-topic on Software Engineering. You need to formulate your question in the context of a concrete problem, that has a single, unambiguous, canonical, objectively correct answer.

– Jörg W Mittag
2 days ago





4




4





@JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

– Caleth
2 days ago





@JörgWMittag I imagine a hypothetical C# that implicitly awaits a Task<T> to convert it to T

– Caleth
2 days ago




5




5





What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

– freakish
2 days ago






What you propose is not doable. It is not up to compiler to decide whether you want to await the result or perhaps fire and forget. Or run in background and await later. Why limit yourself like that?

– freakish
2 days ago





5




5





Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

– Bergi
2 days ago






Yes, it is a terrible idea. Just use async/await instead, which makes the async parts of the execution explicit.

– Bergi
2 days ago





5




5





When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

– Rob
2 days ago





When you say that two things happen concurrently, you are saying that it's ok that these things happen in any order. If your code has no way of making it clear what re-orderings won't break your code's expectations, then it can't make them concurrent.

– Rob
2 days ago










10 Answers
10






active

oldest

votes


















49














Async/await is exactly that automated management that you propose, albeit with two extra keywords. Why are they important? Aside from backwards compatibility?



  • Without explicit points where a coroutine may be suspended and resumed, we would need a type system to detect where an awaitable value must be awaited. Many programming languages do not have such a type system.


  • By making awaiting a value explicit, we can also pass awaitable values around as first class objects: promises. This can be super useful when writing higher-order code.



  • Async code has very deep effects for the execution model of a language, similar to the absence or presence of exceptions in the language. In particular, an async function can only be awaited by async functions. This affects all calling functions! But what if we change a function from non-async to async at the end of this dependency chain? This would be a backwards-incompatible change … unless all functions are async and every function call is awaited by default.



    And that is highly undesirable because it has very bad performance implications. You wouldn't be able to simply return cheap values. Every function call would become a lot more expensive.



Async is great, but some kind of implicit async won't work in reality.



Pure functional languages like Haskell have a bit of an escape hatch because execution order is largely unspecified and unobservable. Or phrased differently: any specific order of operations must be explicitly encoded. That can be rather cumbersome for real-world programs, especially those I/O-heavy programs for which async code is a very good fit.






share|improve this answer


















  • 2





    You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

    – Jörg W Mittag
    2 days ago






  • 6





    @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

    – amon
    2 days ago






  • 7





    @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

    – DarthFennec
    2 days ago






  • 1





    Async/await reminds me of the continuation monad.

    – les
    yesterday






  • 3





    In fact, both exceptions and async/await are instances of algebraic effects.

    – Alex Reinking
    22 hours ago


















13














Some do.



They're not mainstream (yet) because async is a relatively new feature that we've only just now gotten a good feel for if it's even a good feature, or how to present it to programmers in a way that is friendly/usable/expressive/etc. Existing async features are largely bolted onto existing languages, which require a little different design approach.



That said, it's not clearly a good idea to do everywhere. A common failing is doing async calls in a loop, effectively serializing their execution. Having asynchronous calls be implicit may obscure that sort of error. Also, if you support implicit coercion from a Task<T> (or your language's equivalent) to T, that can add a bit of complexity/cost to your typechecker and error reporting when it's unclear which of the two the programmer really wanted.



But those are not insurmountable problems. If you wanted to support that behavior you almost certainly could, though there would be trade-offs.






share|improve this answer


















  • 1





    I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

    – Cinn
    2 days ago







  • 4





    Can you give a few examples for "Some do", please?

    – Bergi
    yesterday






  • 1





    Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

    – Cubic
    yesterday






  • 1





    @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

    – Telastyn
    yesterday


















10














What you are missing, is the purpose of async operations: They allow you to make use of your waiting time!



If you turn an async operation, like requesting some resource from a server, into a synchronous operation by implicitly and immediately waiting for the reply, your thread cannot do anything else with the waiting time. If the server takes 10 milliseconds to respond, there go about 30 million CPU cycles to the waste. The latency of the response becomes the execution time for the request.



The only reason why programmers invented async operations, is to hide the latency of inherently long-running tasks behind other useful computations. If you can fill the waiting time with useful work, that's CPU time saved. If you can't, well, nothing's lost by the operation being async.



So, I recommend to embrace the async operations that your languages provide to you. They are there to save you time.






share|improve this answer























  • i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

    – Cinn
    2 days ago






  • 5





    @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

    – cmaster
    2 days ago











  • Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

    – Cinn
    2 days ago







  • 1





    All computers wait at the same speed.

    – Bob Jarvis
    yesterday











  • @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

    – cmaster
    yesterday


















9














There are languages that do this. But, there is actually not much of a need, since it can be easily accomplished with existing language features.



As long as you have some way of expressing asynchrony, you can implement Futures or Promises purely as a library feature, you don't need any special language features. And as long as you have some of expressing Transparent Proxies, you can put the two features together and you have Transparent Futures.



For example, in Smalltalk and its descendants, an object can change its identity, it can literally "become" a different object (and in fact the method that does this is called Object>>become:).



Imagine a long-running computation that returns a Future<Int>. This Future<Int> has all the same methods as Int, except with different implementations. Future<Int>'s + method does not add another number and return the result, it returns a new Future<Int> which wraps the computation. And so on, and so forth. Methods that cannot sensibly be implemented by returning a Future<Int>, will instead automatically await the result, and then call self become: result., which will make the currently executing object (self, i.e. the Future<Int>) literally become the result object, i.e. from now on the object reference that used to be a Future<Int> is now an Int everywhere, completely transparent to the client.



No special asynchrony-related language features needed.






share|improve this answer























  • Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

    – amon
    2 days ago











  • I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

    – Cinn
    2 days ago











  • @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

    – Jörg W Mittag
    2 days ago






  • 3





    @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

    – Jörg W Mittag
    2 days ago






  • 2





    @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

    – Voo
    16 hours ago



















2














They do (well, most of them). The feature you're looking for is called threads.



Threads have their own problems however:




  1. Because the code can be suspended at any point, you can't ever assume that things won't change "by themselves". When programming with threads, you waste a lot of time thinking about how your program should deal with things changing.



    Imagine a game server is processing a player's attack on another player. Something like this:



    if (playerInMeleeRange(attacker, victim)) 
    const damage = calculateAttackDamage(attacker, victim);
    if (victim.health <= damage)

    // attacker gets whatever the victim was carrying as loot
    const loot = victim.getInventoryItems();
    attacker.addInventoryItems(loot);
    victim.removeInventoryItems(loot);

    victim.sendMessage("$attacker hits you with a $attacker.currentWeapon and you die!");
    victim.setDead();
    else
    victim.health -= damage;
    victim.sendMessage("$attacker hits you with a $attacker.currentWeapon!");

    attacker.markAsKiller();



    Three months later, a player discovers that by getting killed and logging off precisely when attacker.addInventoryItems is running, then victim.removeInventoryItems will fail, he can keep his items and the attacker also gets a copy of his items. He does this several times, creating a million tonnes of gold out of thin air and crashing the game's economy.



    Alternatively, the attacker can log out while the game is sending a message to the victim, and he won't get a "murderer" tag above his head, so his next victim won't run away from him.




  2. Because the code can be suspended at any point, you need to use locks everywhere when manipulating data structures. I gave an example above that has obvious consequences in a game, but it can be more subtle. Consider adding an item to the start of a linked list:



    newItem.nextItem = list.firstItem;
    list.firstItem = newItem;


    This isn't a problem if you say that threads can only be suspended when they're doing I/O, and not at any point. But I'm sure you can imagine a situation where there's an I/O operation - such as logging:



    for (player = playerList.firstItem; player != null; player = item.nextPlayer) 
    debugLog("$item.name is online, they get a gold star");
    // Oops! The player might've logged out while the log message was being written to disk, and now this will throw an exception and the remaining players won't get their gold stars.
    // Or the list might've been rearranged and some players might get two and some players might get none.
    player.addInventoryItem(InventoryItems.GoldStar);



  3. Because the code can be suspended at any point, there could potentially be a lot of state to save. The system deals with this by giving each thread an entirely separate stack. But the stack is quite big, so you can't have more than about 2000 threads in a 32-bit program. Or you could reduce the stack size, at the risk of making it to small.






share|improve this answer






























    1














    The problem you're describing is two-fold.



    • The program you're writing should behave asynchronously as a whole when viewed from the outside.

    • It should not be visible at the call site whether a function call potentially gives up control or not.

    There are a couple of ways to achieve this, but they basically boil down to



    1. having multiple threads (at some level of abstraction)

    2. having multiple kinds of function at the language level, all of which are called like this foo(4, 7, bar, quux).

    For (1), I'm lumping together forking and running multiple processes, spawning multiple kernel threads, and green thread implementations that schedule language-runtime level threads onto kernel threads. From the perspective of the problem, they are the same. In this world, no function ever gives up or loses control from the perspective of its thread. The thread itself sometimes doesn't have control and sometimes isn't running but you don't give up control of your own thread in this world. A system fitting this model may or may not have the ability to spawn new threads or join on existing threads. A system fitting this model may or may not have the ability to duplicate a thread like Unix's fork.



    (2) is interesting. In order to do it justice we need to talk about introduction and elimination forms.



    I'm going to show why implicit await cannot be added to a language like Javascript in a backwards-compatible way. The basic idea is that by exposing promises to the user and having a distinction between synchronous and asynchronous contexts, Javascript has leaked an implementation detail that prevents handling synchronous and asynchronous functions uniformly. There's also the fact that you can't await a promise outside of an async function body. These design choices are incompatible with "making asynchronousness invisible to the caller".



    You can introduce a synchronous function using a lambda and eliminate it with a function call.



    Synchronous function introduction:



    ((x) => return x + x;)


    Synchronous function elimination:



    f(4)

    ((x) => return x + x;)(4)


    You can contrast this with asynchronous function introduction and elimination.



    Asynchronous function introduction



    (async (x) => return x + x;)


    Asynchonrous function elimination (note: only valid inside an async function)



    await (async (x) => return x + x;)(4)


    The fundamental problem here is that an asynchronous function is also a synchronous function producing a promise object.



    Here's an example of calling an asynchronous function synchronously in the node.js repl.



    > (async (x) => return x + x;)(4)
    Promise 8


    You can hypothetically have a language, even a dynamically typed one, where the difference between asynchronous and synchronous function calls is not visible at the call site and possibly is not visible at the definition site.



    Taking a language like that and lowering it to Javascript is possible, you'd just have to effectively make all functions asynchronous.






    share|improve this answer

























    • thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

      – Cinn
      2 days ago


















    1














    If I'm reading you right, you are asking for a synchronous programming model, but a high performance implementation. If that is correct then that is already available to us in the form of green threads or processes of e.g. Erlang or Haskell. So yes, it's an excellent idea, but the retrofitting to existing languages can't always be as smooth as you would like.






    share|improve this answer
































      1














      I appreciate the question, and find the majority of answers to be merely defensive of the status quo. In the spectrum of low- to high-level languages, we've been stuck in a rut for some time. The next higher level is clearly going to be a language that is less focused on syntax (the need for explicit keywords like await and async) and much more about intention. (Obvious credit to Charles Simonyi, but thinking of 2019 and the future.)



      If I told a programmer, write some code that simply fetches a value from a database, you can safely assume I mean, "and BTW, don't hang the UI" and "don't introduce other considerations that mask hard to find bugs". Programmers of the future, with a next-generation of languages and tools, will certainly be able to write code that simply fetches a value in one line of code and goes from there.



      The highest level language would be speaking English, and relying on competence of the task doer to know what you really want done. (Think the computer in Star Trek, or asking something of Alexa.) We're far from that, but inching closer, and my expectation is that the language/compiler could be more to generate robust, intentioned code without going so far as to needing AI.



      On one hand, there are newer visual languages, like Scratch, that do this and aren't bogged down with all the syntactical technicalities. Certainly, there's a lot of behind-the-scenes work going on so the programmer doesn't have to worry about it. That said, I'm not writing business class software in Scratch, so, like you, I have the same expectation that it's time for mature programming languages to automatically manage the synchronous/asynchronous problem.






      share|improve this answer








      New contributor




      Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



























        0














        In the case of Javascript, which you used in your question, there is an important point to be aware of: Javascript is single-threaded, and the order of execution is guaranteed as long as there are no async calls.



        So if you have a sequence like yours:



        const nbOfUsers = getNbOfUsers();


        You are guaranteed that nothing else will be executed in the meantime. No need for locks or anything similar.



        However, if getNbOfUsers is asynchronous, then:



        const nbOfUsers = await getNbOfUsers();


        means that while getNbOfUsers runs, execution yields, and other code may run in between. This may in turn require some locking to happen, depending on what you are doing.



        So, it's a good idea to be aware when a call is asynchronous and when it isn't, as in some situation you will need to take additional precautions you wouldn't need to if the call was synchronous.






        share|improve this answer























        • You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

          – Cinn
          13 hours ago











        • @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

          – jcaron
          12 hours ago


















        -4














        This is available in C++ as std::async since C++11.




        The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.




        And with C++20 coroutines can be used:




        • https://www.modernescpp.com/index.php/coroutines

        • https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await





        share|improve this answer




















        • 5





          This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

          – Arturo Torres Sánchez
          2 days ago











        Your Answer








        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "131"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: false,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );






        Cinn is a new contributor. Be nice, and check out our Code of Conduct.









        draft saved

        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f389445%2fwhy-dont-programming-languages-automatically-manage-the-synchronous-asynchronou%23new-answer', 'question_page');

        );

        Post as a guest















        Required, but never shown




















        StackExchange.ready(function ()
        $("#show-editor-button input, #show-editor-button button").click(function ()
        var showEditor = function()
        $("#show-editor-button").hide();
        $("#post-form").removeClass("dno");
        StackExchange.editor.finallyInit();
        ;

        var useFancy = $(this).data('confirm-use-fancy');
        if(useFancy == 'True')
        var popupTitle = $(this).data('confirm-fancy-title');
        var popupBody = $(this).data('confirm-fancy-body');
        var popupAccept = $(this).data('confirm-fancy-accept-button');

        $(this).loadPopup(
        url: '/post/self-answer-popup',
        loaded: function(popup)
        var pTitle = $(popup).find('h2');
        var pBody = $(popup).find('.popup-body');
        var pSubmit = $(popup).find('.popup-submit');

        pTitle.text(popupTitle);
        pBody.html(popupBody);
        pSubmit.val(popupAccept).click(showEditor);

        )
        else
        var confirmText = $(this).data('confirm-text');
        if (confirmText ? confirm(confirmText) : true)
        showEditor();


        );
        );






        10 Answers
        10






        active

        oldest

        votes








        10 Answers
        10






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        49














        Async/await is exactly that automated management that you propose, albeit with two extra keywords. Why are they important? Aside from backwards compatibility?



        • Without explicit points where a coroutine may be suspended and resumed, we would need a type system to detect where an awaitable value must be awaited. Many programming languages do not have such a type system.


        • By making awaiting a value explicit, we can also pass awaitable values around as first class objects: promises. This can be super useful when writing higher-order code.



        • Async code has very deep effects for the execution model of a language, similar to the absence or presence of exceptions in the language. In particular, an async function can only be awaited by async functions. This affects all calling functions! But what if we change a function from non-async to async at the end of this dependency chain? This would be a backwards-incompatible change … unless all functions are async and every function call is awaited by default.



          And that is highly undesirable because it has very bad performance implications. You wouldn't be able to simply return cheap values. Every function call would become a lot more expensive.



        Async is great, but some kind of implicit async won't work in reality.



        Pure functional languages like Haskell have a bit of an escape hatch because execution order is largely unspecified and unobservable. Or phrased differently: any specific order of operations must be explicitly encoded. That can be rather cumbersome for real-world programs, especially those I/O-heavy programs for which async code is a very good fit.






        share|improve this answer


















        • 2





          You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

          – Jörg W Mittag
          2 days ago






        • 6





          @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

          – amon
          2 days ago






        • 7





          @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

          – DarthFennec
          2 days ago






        • 1





          Async/await reminds me of the continuation monad.

          – les
          yesterday






        • 3





          In fact, both exceptions and async/await are instances of algebraic effects.

          – Alex Reinking
          22 hours ago















        49














        Async/await is exactly that automated management that you propose, albeit with two extra keywords. Why are they important? Aside from backwards compatibility?



        • Without explicit points where a coroutine may be suspended and resumed, we would need a type system to detect where an awaitable value must be awaited. Many programming languages do not have such a type system.


        • By making awaiting a value explicit, we can also pass awaitable values around as first class objects: promises. This can be super useful when writing higher-order code.



        • Async code has very deep effects for the execution model of a language, similar to the absence or presence of exceptions in the language. In particular, an async function can only be awaited by async functions. This affects all calling functions! But what if we change a function from non-async to async at the end of this dependency chain? This would be a backwards-incompatible change … unless all functions are async and every function call is awaited by default.



          And that is highly undesirable because it has very bad performance implications. You wouldn't be able to simply return cheap values. Every function call would become a lot more expensive.



        Async is great, but some kind of implicit async won't work in reality.



        Pure functional languages like Haskell have a bit of an escape hatch because execution order is largely unspecified and unobservable. Or phrased differently: any specific order of operations must be explicitly encoded. That can be rather cumbersome for real-world programs, especially those I/O-heavy programs for which async code is a very good fit.






        share|improve this answer


















        • 2





          You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

          – Jörg W Mittag
          2 days ago






        • 6





          @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

          – amon
          2 days ago






        • 7





          @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

          – DarthFennec
          2 days ago






        • 1





          Async/await reminds me of the continuation monad.

          – les
          yesterday






        • 3





          In fact, both exceptions and async/await are instances of algebraic effects.

          – Alex Reinking
          22 hours ago













        49












        49








        49







        Async/await is exactly that automated management that you propose, albeit with two extra keywords. Why are they important? Aside from backwards compatibility?



        • Without explicit points where a coroutine may be suspended and resumed, we would need a type system to detect where an awaitable value must be awaited. Many programming languages do not have such a type system.


        • By making awaiting a value explicit, we can also pass awaitable values around as first class objects: promises. This can be super useful when writing higher-order code.



        • Async code has very deep effects for the execution model of a language, similar to the absence or presence of exceptions in the language. In particular, an async function can only be awaited by async functions. This affects all calling functions! But what if we change a function from non-async to async at the end of this dependency chain? This would be a backwards-incompatible change … unless all functions are async and every function call is awaited by default.



          And that is highly undesirable because it has very bad performance implications. You wouldn't be able to simply return cheap values. Every function call would become a lot more expensive.



        Async is great, but some kind of implicit async won't work in reality.



        Pure functional languages like Haskell have a bit of an escape hatch because execution order is largely unspecified and unobservable. Or phrased differently: any specific order of operations must be explicitly encoded. That can be rather cumbersome for real-world programs, especially those I/O-heavy programs for which async code is a very good fit.






        share|improve this answer













        Async/await is exactly that automated management that you propose, albeit with two extra keywords. Why are they important? Aside from backwards compatibility?



        • Without explicit points where a coroutine may be suspended and resumed, we would need a type system to detect where an awaitable value must be awaited. Many programming languages do not have such a type system.


        • By making awaiting a value explicit, we can also pass awaitable values around as first class objects: promises. This can be super useful when writing higher-order code.



        • Async code has very deep effects for the execution model of a language, similar to the absence or presence of exceptions in the language. In particular, an async function can only be awaited by async functions. This affects all calling functions! But what if we change a function from non-async to async at the end of this dependency chain? This would be a backwards-incompatible change … unless all functions are async and every function call is awaited by default.



          And that is highly undesirable because it has very bad performance implications. You wouldn't be able to simply return cheap values. Every function call would become a lot more expensive.



        Async is great, but some kind of implicit async won't work in reality.



        Pure functional languages like Haskell have a bit of an escape hatch because execution order is largely unspecified and unobservable. Or phrased differently: any specific order of operations must be explicitly encoded. That can be rather cumbersome for real-world programs, especially those I/O-heavy programs for which async code is a very good fit.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        amonamon

        89.9k21174262




        89.9k21174262







        • 2





          You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

          – Jörg W Mittag
          2 days ago






        • 6





          @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

          – amon
          2 days ago






        • 7





          @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

          – DarthFennec
          2 days ago






        • 1





          Async/await reminds me of the continuation monad.

          – les
          yesterday






        • 3





          In fact, both exceptions and async/await are instances of algebraic effects.

          – Alex Reinking
          22 hours ago












        • 2





          You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

          – Jörg W Mittag
          2 days ago






        • 6





          @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

          – amon
          2 days ago






        • 7





          @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

          – DarthFennec
          2 days ago






        • 1





          Async/await reminds me of the continuation monad.

          – les
          yesterday






        • 3





          In fact, both exceptions and async/await are instances of algebraic effects.

          – Alex Reinking
          22 hours ago







        2




        2





        You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

        – Jörg W Mittag
        2 days ago





        You don't necessarily need a type system. Transparent Futures in e.g. ECMAScript, Smalltalk, Self, Newspeak, Io, Ioke, Seph, can be easily implemented without tyoe system or language support. In Smalltalk and its descendants, an object can transparently change its identity, in ECMAScript, it can transparently change its shape. That is all you need to make Futures transparent, no need for language support for asynchrony.

        – Jörg W Mittag
        2 days ago




        6




        6





        @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

        – amon
        2 days ago





        @JörgWMittag I understand what you're saying and how that could work, but transparent futures without a type system make it rather difficult to simultaneously have first class futures, no? I would need some way to select whether I want to send messages to the future or the future's value, preferably something better than someValue ifItIsAFuture [self| self messageIWantToSend] because that's tricky to integrate with generic code.

        – amon
        2 days ago




        7




        7





        @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

        – DarthFennec
        2 days ago





        @amon "I can write my async code as promises and promises are monads." Monads aren't actually necessary here. Thunks are essentially just promises. Since almost all values in Haskell are boxed, almost all values in Haskell are already promises. That's why you can toss a par pretty much anywhere in pure Haskell code and get paralellism for free.

        – DarthFennec
        2 days ago




        1




        1





        Async/await reminds me of the continuation monad.

        – les
        yesterday





        Async/await reminds me of the continuation monad.

        – les
        yesterday




        3




        3





        In fact, both exceptions and async/await are instances of algebraic effects.

        – Alex Reinking
        22 hours ago





        In fact, both exceptions and async/await are instances of algebraic effects.

        – Alex Reinking
        22 hours ago













        13














        Some do.



        They're not mainstream (yet) because async is a relatively new feature that we've only just now gotten a good feel for if it's even a good feature, or how to present it to programmers in a way that is friendly/usable/expressive/etc. Existing async features are largely bolted onto existing languages, which require a little different design approach.



        That said, it's not clearly a good idea to do everywhere. A common failing is doing async calls in a loop, effectively serializing their execution. Having asynchronous calls be implicit may obscure that sort of error. Also, if you support implicit coercion from a Task<T> (or your language's equivalent) to T, that can add a bit of complexity/cost to your typechecker and error reporting when it's unclear which of the two the programmer really wanted.



        But those are not insurmountable problems. If you wanted to support that behavior you almost certainly could, though there would be trade-offs.






        share|improve this answer


















        • 1





          I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

          – Cinn
          2 days ago







        • 4





          Can you give a few examples for "Some do", please?

          – Bergi
          yesterday






        • 1





          Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

          – Cubic
          yesterday






        • 1





          @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

          – Telastyn
          yesterday















        13














        Some do.



        They're not mainstream (yet) because async is a relatively new feature that we've only just now gotten a good feel for if it's even a good feature, or how to present it to programmers in a way that is friendly/usable/expressive/etc. Existing async features are largely bolted onto existing languages, which require a little different design approach.



        That said, it's not clearly a good idea to do everywhere. A common failing is doing async calls in a loop, effectively serializing their execution. Having asynchronous calls be implicit may obscure that sort of error. Also, if you support implicit coercion from a Task<T> (or your language's equivalent) to T, that can add a bit of complexity/cost to your typechecker and error reporting when it's unclear which of the two the programmer really wanted.



        But those are not insurmountable problems. If you wanted to support that behavior you almost certainly could, though there would be trade-offs.






        share|improve this answer


















        • 1





          I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

          – Cinn
          2 days ago







        • 4





          Can you give a few examples for "Some do", please?

          – Bergi
          yesterday






        • 1





          Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

          – Cubic
          yesterday






        • 1





          @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

          – Telastyn
          yesterday













        13












        13








        13







        Some do.



        They're not mainstream (yet) because async is a relatively new feature that we've only just now gotten a good feel for if it's even a good feature, or how to present it to programmers in a way that is friendly/usable/expressive/etc. Existing async features are largely bolted onto existing languages, which require a little different design approach.



        That said, it's not clearly a good idea to do everywhere. A common failing is doing async calls in a loop, effectively serializing their execution. Having asynchronous calls be implicit may obscure that sort of error. Also, if you support implicit coercion from a Task<T> (or your language's equivalent) to T, that can add a bit of complexity/cost to your typechecker and error reporting when it's unclear which of the two the programmer really wanted.



        But those are not insurmountable problems. If you wanted to support that behavior you almost certainly could, though there would be trade-offs.






        share|improve this answer













        Some do.



        They're not mainstream (yet) because async is a relatively new feature that we've only just now gotten a good feel for if it's even a good feature, or how to present it to programmers in a way that is friendly/usable/expressive/etc. Existing async features are largely bolted onto existing languages, which require a little different design approach.



        That said, it's not clearly a good idea to do everywhere. A common failing is doing async calls in a loop, effectively serializing their execution. Having asynchronous calls be implicit may obscure that sort of error. Also, if you support implicit coercion from a Task<T> (or your language's equivalent) to T, that can add a bit of complexity/cost to your typechecker and error reporting when it's unclear which of the two the programmer really wanted.



        But those are not insurmountable problems. If you wanted to support that behavior you almost certainly could, though there would be trade-offs.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        TelastynTelastyn

        93.9k26210324




        93.9k26210324







        • 1





          I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

          – Cinn
          2 days ago







        • 4





          Can you give a few examples for "Some do", please?

          – Bergi
          yesterday






        • 1





          Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

          – Cubic
          yesterday






        • 1





          @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

          – Telastyn
          yesterday












        • 1





          I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

          – Cinn
          2 days ago







        • 4





          Can you give a few examples for "Some do", please?

          – Bergi
          yesterday






        • 1





          Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

          – Cubic
          yesterday






        • 1





          @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

          – Telastyn
          yesterday







        1




        1





        I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

        – Cinn
        2 days ago






        I think an idea could be to wrap everything in async functions, the synchronous tasks would just resolve immediatly and we get all a one kind to handle (Edit: @amon explained why it's a bad idea...)

        – Cinn
        2 days ago





        4




        4





        Can you give a few examples for "Some do", please?

        – Bergi
        yesterday





        Can you give a few examples for "Some do", please?

        – Bergi
        yesterday




        1




        1





        Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

        – Cubic
        yesterday





        Asynchronous programming isn't in any way new, it's just that nowadays people have to deal with it more often.

        – Cubic
        yesterday




        1




        1





        @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

        – Telastyn
        yesterday





        @Cubic - it is as a language feature as far as I know. Before it was just (awkward) userland functions.

        – Telastyn
        yesterday











        10














        What you are missing, is the purpose of async operations: They allow you to make use of your waiting time!



        If you turn an async operation, like requesting some resource from a server, into a synchronous operation by implicitly and immediately waiting for the reply, your thread cannot do anything else with the waiting time. If the server takes 10 milliseconds to respond, there go about 30 million CPU cycles to the waste. The latency of the response becomes the execution time for the request.



        The only reason why programmers invented async operations, is to hide the latency of inherently long-running tasks behind other useful computations. If you can fill the waiting time with useful work, that's CPU time saved. If you can't, well, nothing's lost by the operation being async.



        So, I recommend to embrace the async operations that your languages provide to you. They are there to save you time.






        share|improve this answer























        • i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

          – Cinn
          2 days ago






        • 5





          @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

          – cmaster
          2 days ago











        • Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

          – Cinn
          2 days ago







        • 1





          All computers wait at the same speed.

          – Bob Jarvis
          yesterday











        • @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

          – cmaster
          yesterday















        10














        What you are missing, is the purpose of async operations: They allow you to make use of your waiting time!



        If you turn an async operation, like requesting some resource from a server, into a synchronous operation by implicitly and immediately waiting for the reply, your thread cannot do anything else with the waiting time. If the server takes 10 milliseconds to respond, there go about 30 million CPU cycles to the waste. The latency of the response becomes the execution time for the request.



        The only reason why programmers invented async operations, is to hide the latency of inherently long-running tasks behind other useful computations. If you can fill the waiting time with useful work, that's CPU time saved. If you can't, well, nothing's lost by the operation being async.



        So, I recommend to embrace the async operations that your languages provide to you. They are there to save you time.






        share|improve this answer























        • i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

          – Cinn
          2 days ago






        • 5





          @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

          – cmaster
          2 days ago











        • Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

          – Cinn
          2 days ago







        • 1





          All computers wait at the same speed.

          – Bob Jarvis
          yesterday











        • @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

          – cmaster
          yesterday













        10












        10








        10







        What you are missing, is the purpose of async operations: They allow you to make use of your waiting time!



        If you turn an async operation, like requesting some resource from a server, into a synchronous operation by implicitly and immediately waiting for the reply, your thread cannot do anything else with the waiting time. If the server takes 10 milliseconds to respond, there go about 30 million CPU cycles to the waste. The latency of the response becomes the execution time for the request.



        The only reason why programmers invented async operations, is to hide the latency of inherently long-running tasks behind other useful computations. If you can fill the waiting time with useful work, that's CPU time saved. If you can't, well, nothing's lost by the operation being async.



        So, I recommend to embrace the async operations that your languages provide to you. They are there to save you time.






        share|improve this answer













        What you are missing, is the purpose of async operations: They allow you to make use of your waiting time!



        If you turn an async operation, like requesting some resource from a server, into a synchronous operation by implicitly and immediately waiting for the reply, your thread cannot do anything else with the waiting time. If the server takes 10 milliseconds to respond, there go about 30 million CPU cycles to the waste. The latency of the response becomes the execution time for the request.



        The only reason why programmers invented async operations, is to hide the latency of inherently long-running tasks behind other useful computations. If you can fill the waiting time with useful work, that's CPU time saved. If you can't, well, nothing's lost by the operation being async.



        So, I recommend to embrace the async operations that your languages provide to you. They are there to save you time.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        cmastercmaster

        6,76311323




        6,76311323












        • i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

          – Cinn
          2 days ago






        • 5





          @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

          – cmaster
          2 days ago











        • Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

          – Cinn
          2 days ago







        • 1





          All computers wait at the same speed.

          – Bob Jarvis
          yesterday











        • @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

          – cmaster
          yesterday

















        • i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

          – Cinn
          2 days ago






        • 5





          @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

          – cmaster
          2 days ago











        • Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

          – Cinn
          2 days ago







        • 1





          All computers wait at the same speed.

          – Bob Jarvis
          yesterday











        • @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

          – cmaster
          yesterday
















        i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

        – Cinn
        2 days ago





        i was thinking of a functional language where operations are not blocking, so even if it has a synchronous syntax, a long-running computation will not block the thread

        – Cinn
        2 days ago




        5




        5





        @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

        – cmaster
        2 days ago





        @Cinn I didn't find that in the question, and the example in the question is Javascript, which does not have this feature. However, generally it's rather hard for a compiler to find meaningful opportunities for parallelization as you describe: Meaningful exploitation of such a feature would require the programmer to explicitly think about what they put right after a long latency call. If you make the runtime smart enough to avoid this requirement on the programmer, your runtime will likely eat up the performance savings because it would need to parallelize aggressively across function calls.

        – cmaster
        2 days ago













        Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

        – Cinn
        2 days ago






        Sorry i have not been clear enough. Btw i agree with you, the runtime will have to be smart enough to contain the function call stack and strike balance between parallelisation and queuing.

        – Cinn
        2 days ago





        1




        1





        All computers wait at the same speed.

        – Bob Jarvis
        yesterday





        All computers wait at the same speed.

        – Bob Jarvis
        yesterday













        @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

        – cmaster
        yesterday





        @BobJarvis Yes. But they differ in how much work they could have done in the waiting time...

        – cmaster
        yesterday











        9














        There are languages that do this. But, there is actually not much of a need, since it can be easily accomplished with existing language features.



        As long as you have some way of expressing asynchrony, you can implement Futures or Promises purely as a library feature, you don't need any special language features. And as long as you have some of expressing Transparent Proxies, you can put the two features together and you have Transparent Futures.



        For example, in Smalltalk and its descendants, an object can change its identity, it can literally "become" a different object (and in fact the method that does this is called Object>>become:).



        Imagine a long-running computation that returns a Future<Int>. This Future<Int> has all the same methods as Int, except with different implementations. Future<Int>'s + method does not add another number and return the result, it returns a new Future<Int> which wraps the computation. And so on, and so forth. Methods that cannot sensibly be implemented by returning a Future<Int>, will instead automatically await the result, and then call self become: result., which will make the currently executing object (self, i.e. the Future<Int>) literally become the result object, i.e. from now on the object reference that used to be a Future<Int> is now an Int everywhere, completely transparent to the client.



        No special asynchrony-related language features needed.






        share|improve this answer























        • Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

          – amon
          2 days ago











        • I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

          – Cinn
          2 days ago











        • @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

          – Jörg W Mittag
          2 days ago






        • 3





          @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

          – Jörg W Mittag
          2 days ago






        • 2





          @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

          – Voo
          16 hours ago
















        9














        There are languages that do this. But, there is actually not much of a need, since it can be easily accomplished with existing language features.



        As long as you have some way of expressing asynchrony, you can implement Futures or Promises purely as a library feature, you don't need any special language features. And as long as you have some of expressing Transparent Proxies, you can put the two features together and you have Transparent Futures.



        For example, in Smalltalk and its descendants, an object can change its identity, it can literally "become" a different object (and in fact the method that does this is called Object>>become:).



        Imagine a long-running computation that returns a Future<Int>. This Future<Int> has all the same methods as Int, except with different implementations. Future<Int>'s + method does not add another number and return the result, it returns a new Future<Int> which wraps the computation. And so on, and so forth. Methods that cannot sensibly be implemented by returning a Future<Int>, will instead automatically await the result, and then call self become: result., which will make the currently executing object (self, i.e. the Future<Int>) literally become the result object, i.e. from now on the object reference that used to be a Future<Int> is now an Int everywhere, completely transparent to the client.



        No special asynchrony-related language features needed.






        share|improve this answer























        • Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

          – amon
          2 days ago











        • I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

          – Cinn
          2 days ago











        • @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

          – Jörg W Mittag
          2 days ago






        • 3





          @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

          – Jörg W Mittag
          2 days ago






        • 2





          @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

          – Voo
          16 hours ago














        9












        9








        9







        There are languages that do this. But, there is actually not much of a need, since it can be easily accomplished with existing language features.



        As long as you have some way of expressing asynchrony, you can implement Futures or Promises purely as a library feature, you don't need any special language features. And as long as you have some of expressing Transparent Proxies, you can put the two features together and you have Transparent Futures.



        For example, in Smalltalk and its descendants, an object can change its identity, it can literally "become" a different object (and in fact the method that does this is called Object>>become:).



        Imagine a long-running computation that returns a Future<Int>. This Future<Int> has all the same methods as Int, except with different implementations. Future<Int>'s + method does not add another number and return the result, it returns a new Future<Int> which wraps the computation. And so on, and so forth. Methods that cannot sensibly be implemented by returning a Future<Int>, will instead automatically await the result, and then call self become: result., which will make the currently executing object (self, i.e. the Future<Int>) literally become the result object, i.e. from now on the object reference that used to be a Future<Int> is now an Int everywhere, completely transparent to the client.



        No special asynchrony-related language features needed.






        share|improve this answer













        There are languages that do this. But, there is actually not much of a need, since it can be easily accomplished with existing language features.



        As long as you have some way of expressing asynchrony, you can implement Futures or Promises purely as a library feature, you don't need any special language features. And as long as you have some of expressing Transparent Proxies, you can put the two features together and you have Transparent Futures.



        For example, in Smalltalk and its descendants, an object can change its identity, it can literally "become" a different object (and in fact the method that does this is called Object>>become:).



        Imagine a long-running computation that returns a Future<Int>. This Future<Int> has all the same methods as Int, except with different implementations. Future<Int>'s + method does not add another number and return the result, it returns a new Future<Int> which wraps the computation. And so on, and so forth. Methods that cannot sensibly be implemented by returning a Future<Int>, will instead automatically await the result, and then call self become: result., which will make the currently executing object (self, i.e. the Future<Int>) literally become the result object, i.e. from now on the object reference that used to be a Future<Int> is now an Int everywhere, completely transparent to the client.



        No special asynchrony-related language features needed.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        Jörg W MittagJörg W Mittag

        69.3k14143227




        69.3k14143227












        • Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

          – amon
          2 days ago











        • I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

          – Cinn
          2 days ago











        • @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

          – Jörg W Mittag
          2 days ago






        • 3





          @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

          – Jörg W Mittag
          2 days ago






        • 2





          @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

          – Voo
          16 hours ago


















        • Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

          – amon
          2 days ago











        • I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

          – Cinn
          2 days ago











        • @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

          – Jörg W Mittag
          2 days ago






        • 3





          @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

          – Jörg W Mittag
          2 days ago






        • 2





          @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

          – Voo
          16 hours ago

















        Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

        – amon
        2 days ago





        Ok, but that has problems if both Future<T> and T share some common interface and I use functionality from that interface. Should it become the result and then use the functionality, or not? I'm thinking of things like an equality operator or a to-string debugging representation.

        – amon
        2 days ago













        I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

        – Cinn
        2 days ago





        I understand that it does not add any features, the thing is we have different syntaxes to write immediately resolving computations and long-running computations, and after that we would use the results the same way for other purposes. I was wondering if we could have a syntax that transparently handle the both, making it more readable and so the programmer does not have to handle it. Like doing a + b, both integers, no matters if a and b are available immediately or later, we just write a + b (making possible to do Int + Future<Int>)

        – Cinn
        2 days ago













        @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

        – Jörg W Mittag
        2 days ago





        @Cinn: Yes, you can do that with Transparent Futures, and you don't need any special language features to do that. You can implement it using the already existing features in e.g. Smalltalk, Self, Newspeak, Us, Korz, Io, Ioke, Seph, ECMAScript, and apparently, as I just read, Python.

        – Jörg W Mittag
        2 days ago




        3




        3





        @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

        – Jörg W Mittag
        2 days ago





        @amon: The idea of Transparent Futures is that you don't know it's a future. From your point of view, there is no common interface between Future<T> and T because from your point of view, there is no Future<T>, only a T. Now, there is of course lots of engineering challenges around how to make this efficient, which operations should be blocking vs. non-blocking, etc., but that is really independent of whether you do it as a language or as a library feature. Transparency was a requirement stipulated by the OP in the question, I won't argue that it is hard and might not make sense.

        – Jörg W Mittag
        2 days ago




        2




        2





        @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

        – Voo
        16 hours ago






        @Jörg That seems like it would be problematic in anything but functional languages since you have no way of knowing when code is actually executed in that model. That generally works fine in say Haskell, but I can't see how this would work in more procedural languages (and even in Haskell, if you care about performance you sometimes have to force an execution and understand the underlying model). An interesting idea nevertheless.

        – Voo
        16 hours ago












        2














        They do (well, most of them). The feature you're looking for is called threads.



        Threads have their own problems however:




        1. Because the code can be suspended at any point, you can't ever assume that things won't change "by themselves". When programming with threads, you waste a lot of time thinking about how your program should deal with things changing.



          Imagine a game server is processing a player's attack on another player. Something like this:



          if (playerInMeleeRange(attacker, victim)) 
          const damage = calculateAttackDamage(attacker, victim);
          if (victim.health <= damage)

          // attacker gets whatever the victim was carrying as loot
          const loot = victim.getInventoryItems();
          attacker.addInventoryItems(loot);
          victim.removeInventoryItems(loot);

          victim.sendMessage("$attacker hits you with a $attacker.currentWeapon and you die!");
          victim.setDead();
          else
          victim.health -= damage;
          victim.sendMessage("$attacker hits you with a $attacker.currentWeapon!");

          attacker.markAsKiller();



          Three months later, a player discovers that by getting killed and logging off precisely when attacker.addInventoryItems is running, then victim.removeInventoryItems will fail, he can keep his items and the attacker also gets a copy of his items. He does this several times, creating a million tonnes of gold out of thin air and crashing the game's economy.



          Alternatively, the attacker can log out while the game is sending a message to the victim, and he won't get a "murderer" tag above his head, so his next victim won't run away from him.




        2. Because the code can be suspended at any point, you need to use locks everywhere when manipulating data structures. I gave an example above that has obvious consequences in a game, but it can be more subtle. Consider adding an item to the start of a linked list:



          newItem.nextItem = list.firstItem;
          list.firstItem = newItem;


          This isn't a problem if you say that threads can only be suspended when they're doing I/O, and not at any point. But I'm sure you can imagine a situation where there's an I/O operation - such as logging:



          for (player = playerList.firstItem; player != null; player = item.nextPlayer) 
          debugLog("$item.name is online, they get a gold star");
          // Oops! The player might've logged out while the log message was being written to disk, and now this will throw an exception and the remaining players won't get their gold stars.
          // Or the list might've been rearranged and some players might get two and some players might get none.
          player.addInventoryItem(InventoryItems.GoldStar);



        3. Because the code can be suspended at any point, there could potentially be a lot of state to save. The system deals with this by giving each thread an entirely separate stack. But the stack is quite big, so you can't have more than about 2000 threads in a 32-bit program. Or you could reduce the stack size, at the risk of making it to small.






        share|improve this answer



























          2














          They do (well, most of them). The feature you're looking for is called threads.



          Threads have their own problems however:




          1. Because the code can be suspended at any point, you can't ever assume that things won't change "by themselves". When programming with threads, you waste a lot of time thinking about how your program should deal with things changing.



            Imagine a game server is processing a player's attack on another player. Something like this:



            if (playerInMeleeRange(attacker, victim)) 
            const damage = calculateAttackDamage(attacker, victim);
            if (victim.health <= damage)

            // attacker gets whatever the victim was carrying as loot
            const loot = victim.getInventoryItems();
            attacker.addInventoryItems(loot);
            victim.removeInventoryItems(loot);

            victim.sendMessage("$attacker hits you with a $attacker.currentWeapon and you die!");
            victim.setDead();
            else
            victim.health -= damage;
            victim.sendMessage("$attacker hits you with a $attacker.currentWeapon!");

            attacker.markAsKiller();



            Three months later, a player discovers that by getting killed and logging off precisely when attacker.addInventoryItems is running, then victim.removeInventoryItems will fail, he can keep his items and the attacker also gets a copy of his items. He does this several times, creating a million tonnes of gold out of thin air and crashing the game's economy.



            Alternatively, the attacker can log out while the game is sending a message to the victim, and he won't get a "murderer" tag above his head, so his next victim won't run away from him.




          2. Because the code can be suspended at any point, you need to use locks everywhere when manipulating data structures. I gave an example above that has obvious consequences in a game, but it can be more subtle. Consider adding an item to the start of a linked list:



            newItem.nextItem = list.firstItem;
            list.firstItem = newItem;


            This isn't a problem if you say that threads can only be suspended when they're doing I/O, and not at any point. But I'm sure you can imagine a situation where there's an I/O operation - such as logging:



            for (player = playerList.firstItem; player != null; player = item.nextPlayer) 
            debugLog("$item.name is online, they get a gold star");
            // Oops! The player might've logged out while the log message was being written to disk, and now this will throw an exception and the remaining players won't get their gold stars.
            // Or the list might've been rearranged and some players might get two and some players might get none.
            player.addInventoryItem(InventoryItems.GoldStar);



          3. Because the code can be suspended at any point, there could potentially be a lot of state to save. The system deals with this by giving each thread an entirely separate stack. But the stack is quite big, so you can't have more than about 2000 threads in a 32-bit program. Or you could reduce the stack size, at the risk of making it to small.






          share|improve this answer

























            2












            2








            2







            They do (well, most of them). The feature you're looking for is called threads.



            Threads have their own problems however:




            1. Because the code can be suspended at any point, you can't ever assume that things won't change "by themselves". When programming with threads, you waste a lot of time thinking about how your program should deal with things changing.



              Imagine a game server is processing a player's attack on another player. Something like this:



              if (playerInMeleeRange(attacker, victim)) 
              const damage = calculateAttackDamage(attacker, victim);
              if (victim.health <= damage)

              // attacker gets whatever the victim was carrying as loot
              const loot = victim.getInventoryItems();
              attacker.addInventoryItems(loot);
              victim.removeInventoryItems(loot);

              victim.sendMessage("$attacker hits you with a $attacker.currentWeapon and you die!");
              victim.setDead();
              else
              victim.health -= damage;
              victim.sendMessage("$attacker hits you with a $attacker.currentWeapon!");

              attacker.markAsKiller();



              Three months later, a player discovers that by getting killed and logging off precisely when attacker.addInventoryItems is running, then victim.removeInventoryItems will fail, he can keep his items and the attacker also gets a copy of his items. He does this several times, creating a million tonnes of gold out of thin air and crashing the game's economy.



              Alternatively, the attacker can log out while the game is sending a message to the victim, and he won't get a "murderer" tag above his head, so his next victim won't run away from him.




            2. Because the code can be suspended at any point, you need to use locks everywhere when manipulating data structures. I gave an example above that has obvious consequences in a game, but it can be more subtle. Consider adding an item to the start of a linked list:



              newItem.nextItem = list.firstItem;
              list.firstItem = newItem;


              This isn't a problem if you say that threads can only be suspended when they're doing I/O, and not at any point. But I'm sure you can imagine a situation where there's an I/O operation - such as logging:



              for (player = playerList.firstItem; player != null; player = item.nextPlayer) 
              debugLog("$item.name is online, they get a gold star");
              // Oops! The player might've logged out while the log message was being written to disk, and now this will throw an exception and the remaining players won't get their gold stars.
              // Or the list might've been rearranged and some players might get two and some players might get none.
              player.addInventoryItem(InventoryItems.GoldStar);



            3. Because the code can be suspended at any point, there could potentially be a lot of state to save. The system deals with this by giving each thread an entirely separate stack. But the stack is quite big, so you can't have more than about 2000 threads in a 32-bit program. Or you could reduce the stack size, at the risk of making it to small.






            share|improve this answer













            They do (well, most of them). The feature you're looking for is called threads.



            Threads have their own problems however:




            1. Because the code can be suspended at any point, you can't ever assume that things won't change "by themselves". When programming with threads, you waste a lot of time thinking about how your program should deal with things changing.



              Imagine a game server is processing a player's attack on another player. Something like this:



              if (playerInMeleeRange(attacker, victim)) 
              const damage = calculateAttackDamage(attacker, victim);
              if (victim.health <= damage)

              // attacker gets whatever the victim was carrying as loot
              const loot = victim.getInventoryItems();
              attacker.addInventoryItems(loot);
              victim.removeInventoryItems(loot);

              victim.sendMessage("$attacker hits you with a $attacker.currentWeapon and you die!");
              victim.setDead();
              else
              victim.health -= damage;
              victim.sendMessage("$attacker hits you with a $attacker.currentWeapon!");

              attacker.markAsKiller();



              Three months later, a player discovers that by getting killed and logging off precisely when attacker.addInventoryItems is running, then victim.removeInventoryItems will fail, he can keep his items and the attacker also gets a copy of his items. He does this several times, creating a million tonnes of gold out of thin air and crashing the game's economy.



              Alternatively, the attacker can log out while the game is sending a message to the victim, and he won't get a "murderer" tag above his head, so his next victim won't run away from him.




            2. Because the code can be suspended at any point, you need to use locks everywhere when manipulating data structures. I gave an example above that has obvious consequences in a game, but it can be more subtle. Consider adding an item to the start of a linked list:



              newItem.nextItem = list.firstItem;
              list.firstItem = newItem;


              This isn't a problem if you say that threads can only be suspended when they're doing I/O, and not at any point. But I'm sure you can imagine a situation where there's an I/O operation - such as logging:



              for (player = playerList.firstItem; player != null; player = item.nextPlayer) 
              debugLog("$item.name is online, they get a gold star");
              // Oops! The player might've logged out while the log message was being written to disk, and now this will throw an exception and the remaining players won't get their gold stars.
              // Or the list might've been rearranged and some players might get two and some players might get none.
              player.addInventoryItem(InventoryItems.GoldStar);



            3. Because the code can be suspended at any point, there could potentially be a lot of state to save. The system deals with this by giving each thread an entirely separate stack. But the stack is quite big, so you can't have more than about 2000 threads in a 32-bit program. Or you could reduce the stack size, at the risk of making it to small.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 5 hours ago









            immibisimmibis

            1,78721215




            1,78721215





















                1














                The problem you're describing is two-fold.



                • The program you're writing should behave asynchronously as a whole when viewed from the outside.

                • It should not be visible at the call site whether a function call potentially gives up control or not.

                There are a couple of ways to achieve this, but they basically boil down to



                1. having multiple threads (at some level of abstraction)

                2. having multiple kinds of function at the language level, all of which are called like this foo(4, 7, bar, quux).

                For (1), I'm lumping together forking and running multiple processes, spawning multiple kernel threads, and green thread implementations that schedule language-runtime level threads onto kernel threads. From the perspective of the problem, they are the same. In this world, no function ever gives up or loses control from the perspective of its thread. The thread itself sometimes doesn't have control and sometimes isn't running but you don't give up control of your own thread in this world. A system fitting this model may or may not have the ability to spawn new threads or join on existing threads. A system fitting this model may or may not have the ability to duplicate a thread like Unix's fork.



                (2) is interesting. In order to do it justice we need to talk about introduction and elimination forms.



                I'm going to show why implicit await cannot be added to a language like Javascript in a backwards-compatible way. The basic idea is that by exposing promises to the user and having a distinction between synchronous and asynchronous contexts, Javascript has leaked an implementation detail that prevents handling synchronous and asynchronous functions uniformly. There's also the fact that you can't await a promise outside of an async function body. These design choices are incompatible with "making asynchronousness invisible to the caller".



                You can introduce a synchronous function using a lambda and eliminate it with a function call.



                Synchronous function introduction:



                ((x) => return x + x;)


                Synchronous function elimination:



                f(4)

                ((x) => return x + x;)(4)


                You can contrast this with asynchronous function introduction and elimination.



                Asynchronous function introduction



                (async (x) => return x + x;)


                Asynchonrous function elimination (note: only valid inside an async function)



                await (async (x) => return x + x;)(4)


                The fundamental problem here is that an asynchronous function is also a synchronous function producing a promise object.



                Here's an example of calling an asynchronous function synchronously in the node.js repl.



                > (async (x) => return x + x;)(4)
                Promise 8


                You can hypothetically have a language, even a dynamically typed one, where the difference between asynchronous and synchronous function calls is not visible at the call site and possibly is not visible at the definition site.



                Taking a language like that and lowering it to Javascript is possible, you'd just have to effectively make all functions asynchronous.






                share|improve this answer

























                • thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                  – Cinn
                  2 days ago















                1














                The problem you're describing is two-fold.



                • The program you're writing should behave asynchronously as a whole when viewed from the outside.

                • It should not be visible at the call site whether a function call potentially gives up control or not.

                There are a couple of ways to achieve this, but they basically boil down to



                1. having multiple threads (at some level of abstraction)

                2. having multiple kinds of function at the language level, all of which are called like this foo(4, 7, bar, quux).

                For (1), I'm lumping together forking and running multiple processes, spawning multiple kernel threads, and green thread implementations that schedule language-runtime level threads onto kernel threads. From the perspective of the problem, they are the same. In this world, no function ever gives up or loses control from the perspective of its thread. The thread itself sometimes doesn't have control and sometimes isn't running but you don't give up control of your own thread in this world. A system fitting this model may or may not have the ability to spawn new threads or join on existing threads. A system fitting this model may or may not have the ability to duplicate a thread like Unix's fork.



                (2) is interesting. In order to do it justice we need to talk about introduction and elimination forms.



                I'm going to show why implicit await cannot be added to a language like Javascript in a backwards-compatible way. The basic idea is that by exposing promises to the user and having a distinction between synchronous and asynchronous contexts, Javascript has leaked an implementation detail that prevents handling synchronous and asynchronous functions uniformly. There's also the fact that you can't await a promise outside of an async function body. These design choices are incompatible with "making asynchronousness invisible to the caller".



                You can introduce a synchronous function using a lambda and eliminate it with a function call.



                Synchronous function introduction:



                ((x) => return x + x;)


                Synchronous function elimination:



                f(4)

                ((x) => return x + x;)(4)


                You can contrast this with asynchronous function introduction and elimination.



                Asynchronous function introduction



                (async (x) => return x + x;)


                Asynchonrous function elimination (note: only valid inside an async function)



                await (async (x) => return x + x;)(4)


                The fundamental problem here is that an asynchronous function is also a synchronous function producing a promise object.



                Here's an example of calling an asynchronous function synchronously in the node.js repl.



                > (async (x) => return x + x;)(4)
                Promise 8


                You can hypothetically have a language, even a dynamically typed one, where the difference between asynchronous and synchronous function calls is not visible at the call site and possibly is not visible at the definition site.



                Taking a language like that and lowering it to Javascript is possible, you'd just have to effectively make all functions asynchronous.






                share|improve this answer

























                • thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                  – Cinn
                  2 days ago













                1












                1








                1







                The problem you're describing is two-fold.



                • The program you're writing should behave asynchronously as a whole when viewed from the outside.

                • It should not be visible at the call site whether a function call potentially gives up control or not.

                There are a couple of ways to achieve this, but they basically boil down to



                1. having multiple threads (at some level of abstraction)

                2. having multiple kinds of function at the language level, all of which are called like this foo(4, 7, bar, quux).

                For (1), I'm lumping together forking and running multiple processes, spawning multiple kernel threads, and green thread implementations that schedule language-runtime level threads onto kernel threads. From the perspective of the problem, they are the same. In this world, no function ever gives up or loses control from the perspective of its thread. The thread itself sometimes doesn't have control and sometimes isn't running but you don't give up control of your own thread in this world. A system fitting this model may or may not have the ability to spawn new threads or join on existing threads. A system fitting this model may or may not have the ability to duplicate a thread like Unix's fork.



                (2) is interesting. In order to do it justice we need to talk about introduction and elimination forms.



                I'm going to show why implicit await cannot be added to a language like Javascript in a backwards-compatible way. The basic idea is that by exposing promises to the user and having a distinction between synchronous and asynchronous contexts, Javascript has leaked an implementation detail that prevents handling synchronous and asynchronous functions uniformly. There's also the fact that you can't await a promise outside of an async function body. These design choices are incompatible with "making asynchronousness invisible to the caller".



                You can introduce a synchronous function using a lambda and eliminate it with a function call.



                Synchronous function introduction:



                ((x) => return x + x;)


                Synchronous function elimination:



                f(4)

                ((x) => return x + x;)(4)


                You can contrast this with asynchronous function introduction and elimination.



                Asynchronous function introduction



                (async (x) => return x + x;)


                Asynchonrous function elimination (note: only valid inside an async function)



                await (async (x) => return x + x;)(4)


                The fundamental problem here is that an asynchronous function is also a synchronous function producing a promise object.



                Here's an example of calling an asynchronous function synchronously in the node.js repl.



                > (async (x) => return x + x;)(4)
                Promise 8


                You can hypothetically have a language, even a dynamically typed one, where the difference between asynchronous and synchronous function calls is not visible at the call site and possibly is not visible at the definition site.



                Taking a language like that and lowering it to Javascript is possible, you'd just have to effectively make all functions asynchronous.






                share|improve this answer















                The problem you're describing is two-fold.



                • The program you're writing should behave asynchronously as a whole when viewed from the outside.

                • It should not be visible at the call site whether a function call potentially gives up control or not.

                There are a couple of ways to achieve this, but they basically boil down to



                1. having multiple threads (at some level of abstraction)

                2. having multiple kinds of function at the language level, all of which are called like this foo(4, 7, bar, quux).

                For (1), I'm lumping together forking and running multiple processes, spawning multiple kernel threads, and green thread implementations that schedule language-runtime level threads onto kernel threads. From the perspective of the problem, they are the same. In this world, no function ever gives up or loses control from the perspective of its thread. The thread itself sometimes doesn't have control and sometimes isn't running but you don't give up control of your own thread in this world. A system fitting this model may or may not have the ability to spawn new threads or join on existing threads. A system fitting this model may or may not have the ability to duplicate a thread like Unix's fork.



                (2) is interesting. In order to do it justice we need to talk about introduction and elimination forms.



                I'm going to show why implicit await cannot be added to a language like Javascript in a backwards-compatible way. The basic idea is that by exposing promises to the user and having a distinction between synchronous and asynchronous contexts, Javascript has leaked an implementation detail that prevents handling synchronous and asynchronous functions uniformly. There's also the fact that you can't await a promise outside of an async function body. These design choices are incompatible with "making asynchronousness invisible to the caller".



                You can introduce a synchronous function using a lambda and eliminate it with a function call.



                Synchronous function introduction:



                ((x) => return x + x;)


                Synchronous function elimination:



                f(4)

                ((x) => return x + x;)(4)


                You can contrast this with asynchronous function introduction and elimination.



                Asynchronous function introduction



                (async (x) => return x + x;)


                Asynchonrous function elimination (note: only valid inside an async function)



                await (async (x) => return x + x;)(4)


                The fundamental problem here is that an asynchronous function is also a synchronous function producing a promise object.



                Here's an example of calling an asynchronous function synchronously in the node.js repl.



                > (async (x) => return x + x;)(4)
                Promise 8


                You can hypothetically have a language, even a dynamically typed one, where the difference between asynchronous and synchronous function calls is not visible at the call site and possibly is not visible at the definition site.



                Taking a language like that and lowering it to Javascript is possible, you'd just have to effectively make all functions asynchronous.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 2 days ago

























                answered 2 days ago









                Gregory NisbetGregory Nisbet

                1836




                1836












                • thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                  – Cinn
                  2 days ago

















                • thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                  – Cinn
                  2 days ago
















                thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                – Cinn
                2 days ago





                thanks for those details, i was actually thinking to try it using a js parser (esprima/acorn/cherow/whatever), using the estree to understand what is sync and async and then writing down javascript

                – Cinn
                2 days ago











                1














                If I'm reading you right, you are asking for a synchronous programming model, but a high performance implementation. If that is correct then that is already available to us in the form of green threads or processes of e.g. Erlang or Haskell. So yes, it's an excellent idea, but the retrofitting to existing languages can't always be as smooth as you would like.






                share|improve this answer





























                  1














                  If I'm reading you right, you are asking for a synchronous programming model, but a high performance implementation. If that is correct then that is already available to us in the form of green threads or processes of e.g. Erlang or Haskell. So yes, it's an excellent idea, but the retrofitting to existing languages can't always be as smooth as you would like.






                  share|improve this answer



























                    1












                    1








                    1







                    If I'm reading you right, you are asking for a synchronous programming model, but a high performance implementation. If that is correct then that is already available to us in the form of green threads or processes of e.g. Erlang or Haskell. So yes, it's an excellent idea, but the retrofitting to existing languages can't always be as smooth as you would like.






                    share|improve this answer















                    If I'm reading you right, you are asking for a synchronous programming model, but a high performance implementation. If that is correct then that is already available to us in the form of green threads or processes of e.g. Erlang or Haskell. So yes, it's an excellent idea, but the retrofitting to existing languages can't always be as smooth as you would like.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited yesterday









                    Peter Mortensen

                    1,11521114




                    1,11521114










                    answered 2 days ago









                    monocellmonocell

                    1466




                    1466





















                        1














                        I appreciate the question, and find the majority of answers to be merely defensive of the status quo. In the spectrum of low- to high-level languages, we've been stuck in a rut for some time. The next higher level is clearly going to be a language that is less focused on syntax (the need for explicit keywords like await and async) and much more about intention. (Obvious credit to Charles Simonyi, but thinking of 2019 and the future.)



                        If I told a programmer, write some code that simply fetches a value from a database, you can safely assume I mean, "and BTW, don't hang the UI" and "don't introduce other considerations that mask hard to find bugs". Programmers of the future, with a next-generation of languages and tools, will certainly be able to write code that simply fetches a value in one line of code and goes from there.



                        The highest level language would be speaking English, and relying on competence of the task doer to know what you really want done. (Think the computer in Star Trek, or asking something of Alexa.) We're far from that, but inching closer, and my expectation is that the language/compiler could be more to generate robust, intentioned code without going so far as to needing AI.



                        On one hand, there are newer visual languages, like Scratch, that do this and aren't bogged down with all the syntactical technicalities. Certainly, there's a lot of behind-the-scenes work going on so the programmer doesn't have to worry about it. That said, I'm not writing business class software in Scratch, so, like you, I have the same expectation that it's time for mature programming languages to automatically manage the synchronous/asynchronous problem.






                        share|improve this answer








                        New contributor




                        Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.
























                          1














                          I appreciate the question, and find the majority of answers to be merely defensive of the status quo. In the spectrum of low- to high-level languages, we've been stuck in a rut for some time. The next higher level is clearly going to be a language that is less focused on syntax (the need for explicit keywords like await and async) and much more about intention. (Obvious credit to Charles Simonyi, but thinking of 2019 and the future.)



                          If I told a programmer, write some code that simply fetches a value from a database, you can safely assume I mean, "and BTW, don't hang the UI" and "don't introduce other considerations that mask hard to find bugs". Programmers of the future, with a next-generation of languages and tools, will certainly be able to write code that simply fetches a value in one line of code and goes from there.



                          The highest level language would be speaking English, and relying on competence of the task doer to know what you really want done. (Think the computer in Star Trek, or asking something of Alexa.) We're far from that, but inching closer, and my expectation is that the language/compiler could be more to generate robust, intentioned code without going so far as to needing AI.



                          On one hand, there are newer visual languages, like Scratch, that do this and aren't bogged down with all the syntactical technicalities. Certainly, there's a lot of behind-the-scenes work going on so the programmer doesn't have to worry about it. That said, I'm not writing business class software in Scratch, so, like you, I have the same expectation that it's time for mature programming languages to automatically manage the synchronous/asynchronous problem.






                          share|improve this answer








                          New contributor




                          Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






















                            1












                            1








                            1







                            I appreciate the question, and find the majority of answers to be merely defensive of the status quo. In the spectrum of low- to high-level languages, we've been stuck in a rut for some time. The next higher level is clearly going to be a language that is less focused on syntax (the need for explicit keywords like await and async) and much more about intention. (Obvious credit to Charles Simonyi, but thinking of 2019 and the future.)



                            If I told a programmer, write some code that simply fetches a value from a database, you can safely assume I mean, "and BTW, don't hang the UI" and "don't introduce other considerations that mask hard to find bugs". Programmers of the future, with a next-generation of languages and tools, will certainly be able to write code that simply fetches a value in one line of code and goes from there.



                            The highest level language would be speaking English, and relying on competence of the task doer to know what you really want done. (Think the computer in Star Trek, or asking something of Alexa.) We're far from that, but inching closer, and my expectation is that the language/compiler could be more to generate robust, intentioned code without going so far as to needing AI.



                            On one hand, there are newer visual languages, like Scratch, that do this and aren't bogged down with all the syntactical technicalities. Certainly, there's a lot of behind-the-scenes work going on so the programmer doesn't have to worry about it. That said, I'm not writing business class software in Scratch, so, like you, I have the same expectation that it's time for mature programming languages to automatically manage the synchronous/asynchronous problem.






                            share|improve this answer








                            New contributor




                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.










                            I appreciate the question, and find the majority of answers to be merely defensive of the status quo. In the spectrum of low- to high-level languages, we've been stuck in a rut for some time. The next higher level is clearly going to be a language that is less focused on syntax (the need for explicit keywords like await and async) and much more about intention. (Obvious credit to Charles Simonyi, but thinking of 2019 and the future.)



                            If I told a programmer, write some code that simply fetches a value from a database, you can safely assume I mean, "and BTW, don't hang the UI" and "don't introduce other considerations that mask hard to find bugs". Programmers of the future, with a next-generation of languages and tools, will certainly be able to write code that simply fetches a value in one line of code and goes from there.



                            The highest level language would be speaking English, and relying on competence of the task doer to know what you really want done. (Think the computer in Star Trek, or asking something of Alexa.) We're far from that, but inching closer, and my expectation is that the language/compiler could be more to generate robust, intentioned code without going so far as to needing AI.



                            On one hand, there are newer visual languages, like Scratch, that do this and aren't bogged down with all the syntactical technicalities. Certainly, there's a lot of behind-the-scenes work going on so the programmer doesn't have to worry about it. That said, I'm not writing business class software in Scratch, so, like you, I have the same expectation that it's time for mature programming languages to automatically manage the synchronous/asynchronous problem.







                            share|improve this answer








                            New contributor




                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            share|improve this answer



                            share|improve this answer






                            New contributor




                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            answered yesterday









                            Mikey WetzelMikey Wetzel

                            271




                            271




                            New contributor




                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.





                            New contributor





                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






                            Mikey Wetzel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.





















                                0














                                In the case of Javascript, which you used in your question, there is an important point to be aware of: Javascript is single-threaded, and the order of execution is guaranteed as long as there are no async calls.



                                So if you have a sequence like yours:



                                const nbOfUsers = getNbOfUsers();


                                You are guaranteed that nothing else will be executed in the meantime. No need for locks or anything similar.



                                However, if getNbOfUsers is asynchronous, then:



                                const nbOfUsers = await getNbOfUsers();


                                means that while getNbOfUsers runs, execution yields, and other code may run in between. This may in turn require some locking to happen, depending on what you are doing.



                                So, it's a good idea to be aware when a call is asynchronous and when it isn't, as in some situation you will need to take additional precautions you wouldn't need to if the call was synchronous.






                                share|improve this answer























                                • You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                  – Cinn
                                  13 hours ago











                                • @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                  – jcaron
                                  12 hours ago















                                0














                                In the case of Javascript, which you used in your question, there is an important point to be aware of: Javascript is single-threaded, and the order of execution is guaranteed as long as there are no async calls.



                                So if you have a sequence like yours:



                                const nbOfUsers = getNbOfUsers();


                                You are guaranteed that nothing else will be executed in the meantime. No need for locks or anything similar.



                                However, if getNbOfUsers is asynchronous, then:



                                const nbOfUsers = await getNbOfUsers();


                                means that while getNbOfUsers runs, execution yields, and other code may run in between. This may in turn require some locking to happen, depending on what you are doing.



                                So, it's a good idea to be aware when a call is asynchronous and when it isn't, as in some situation you will need to take additional precautions you wouldn't need to if the call was synchronous.






                                share|improve this answer























                                • You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                  – Cinn
                                  13 hours ago











                                • @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                  – jcaron
                                  12 hours ago













                                0












                                0








                                0







                                In the case of Javascript, which you used in your question, there is an important point to be aware of: Javascript is single-threaded, and the order of execution is guaranteed as long as there are no async calls.



                                So if you have a sequence like yours:



                                const nbOfUsers = getNbOfUsers();


                                You are guaranteed that nothing else will be executed in the meantime. No need for locks or anything similar.



                                However, if getNbOfUsers is asynchronous, then:



                                const nbOfUsers = await getNbOfUsers();


                                means that while getNbOfUsers runs, execution yields, and other code may run in between. This may in turn require some locking to happen, depending on what you are doing.



                                So, it's a good idea to be aware when a call is asynchronous and when it isn't, as in some situation you will need to take additional precautions you wouldn't need to if the call was synchronous.






                                share|improve this answer













                                In the case of Javascript, which you used in your question, there is an important point to be aware of: Javascript is single-threaded, and the order of execution is guaranteed as long as there are no async calls.



                                So if you have a sequence like yours:



                                const nbOfUsers = getNbOfUsers();


                                You are guaranteed that nothing else will be executed in the meantime. No need for locks or anything similar.



                                However, if getNbOfUsers is asynchronous, then:



                                const nbOfUsers = await getNbOfUsers();


                                means that while getNbOfUsers runs, execution yields, and other code may run in between. This may in turn require some locking to happen, depending on what you are doing.



                                So, it's a good idea to be aware when a call is asynchronous and when it isn't, as in some situation you will need to take additional precautions you wouldn't need to if the call was synchronous.







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered yesterday









                                jcaronjcaron

                                1415




                                1415












                                • You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                  – Cinn
                                  13 hours ago











                                • @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                  – jcaron
                                  12 hours ago

















                                • You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                  – Cinn
                                  13 hours ago











                                • @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                  – jcaron
                                  12 hours ago
















                                You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                – Cinn
                                13 hours ago





                                You are right, my second code in the question is invalid as if getNbOfUsers() returns a Promise. But that is exactly the point of my question, why do we need to explicitly write it as asynchronous, the compiler could detect it and handle it automatically in a different way.

                                – Cinn
                                13 hours ago













                                @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                – jcaron
                                12 hours ago





                                @Cinn that’s not my point. My point is that the execution flow may get to other parts of your code during the execution of the asynchronous call, while it isn’t possible for a synchronous call. It would be like having multiple threads running but not being aware of it. This can end up in big issues (which are usually hard to detect and reproduce).

                                – jcaron
                                12 hours ago











                                -4














                                This is available in C++ as std::async since C++11.




                                The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.




                                And with C++20 coroutines can be used:




                                • https://www.modernescpp.com/index.php/coroutines

                                • https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await





                                share|improve this answer




















                                • 5





                                  This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                  – Arturo Torres Sánchez
                                  2 days ago















                                -4














                                This is available in C++ as std::async since C++11.




                                The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.




                                And with C++20 coroutines can be used:




                                • https://www.modernescpp.com/index.php/coroutines

                                • https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await





                                share|improve this answer




















                                • 5





                                  This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                  – Arturo Torres Sánchez
                                  2 days ago













                                -4












                                -4








                                -4







                                This is available in C++ as std::async since C++11.




                                The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.




                                And with C++20 coroutines can be used:




                                • https://www.modernescpp.com/index.php/coroutines

                                • https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await





                                share|improve this answer















                                This is available in C++ as std::async since C++11.




                                The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.




                                And with C++20 coroutines can be used:




                                • https://www.modernescpp.com/index.php/coroutines

                                • https://lewissbaker.github.io/2017/11/17/understanding-operator-co-await






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited 2 days ago

























                                answered 2 days ago









                                Robert AndrzejukRobert Andrzejuk

                                513110




                                513110







                                • 5





                                  This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                  – Arturo Torres Sánchez
                                  2 days ago












                                • 5





                                  This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                  – Arturo Torres Sánchez
                                  2 days ago







                                5




                                5





                                This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                – Arturo Torres Sánchez
                                2 days ago





                                This doesn't seem to answer the question. According to your link: "What does the Coroutines TS give us? Three new language keywords: co_await, co_yield and co_return"... But the question is why do we need an await (or co_await in this case) keyword in the first place?

                                – Arturo Torres Sánchez
                                2 days ago










                                Cinn is a new contributor. Be nice, and check out our Code of Conduct.









                                draft saved

                                draft discarded


















                                Cinn is a new contributor. Be nice, and check out our Code of Conduct.












                                Cinn is a new contributor. Be nice, and check out our Code of Conduct.











                                Cinn is a new contributor. Be nice, and check out our Code of Conduct.














                                Thanks for contributing an answer to Software Engineering Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid


                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.

                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f389445%2fwhy-dont-programming-languages-automatically-manage-the-synchronous-asynchronou%23new-answer', 'question_page');

                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown











                                Popular posts from this blog

                                getting Checkpoint VPN SSL Network Extender working in the command lineHow to connect to CheckPoint VPN on Ubuntu 18.04LTS?Will the Linux ( red-hat ) Open VPNC Client connect to checkpoint or nortel VPN gateways?VPN client for linux machine + support checkpoint gatewayVPN SSL Network Extender in FirefoxLinux Checkpoint SNX tool configuration issuesCheck Point - Connect under Linux - snx + OTPSNX VPN Ububuntu 18.XXUsing Checkpoint VPN SSL Network Extender CLI with certificateVPN with network manager (nm-applet) is not workingWill the Linux ( red-hat ) Open VPNC Client connect to checkpoint or nortel VPN gateways?VPN client for linux machine + support checkpoint gatewayImport VPN config files to NetworkManager from command lineTrouble connecting to VPN using network-manager, while command line worksStart a VPN connection with PPTP protocol on command linestarting a docker service daemon breaks the vpn networkCan't connect to vpn with Network-managerVPN SSL Network Extender in FirefoxUsing Checkpoint VPN SSL Network Extender CLI with certificate

                                Cannot Extend partition with GParted The 2019 Stack Overflow Developer Survey Results Are In Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) 2019 Community Moderator Election ResultsCan't increase partition size with GParted?GParted doesn't recognize the unallocated space after my current partitionWhat is the best way to add unallocated space located before to Ubuntu 12.04 partition with GParted live?I can't figure out how to extend my Arch home partition into free spaceGparted Linux Mint 18.1 issueTrying to extend but swap partition is showing as Unknown in Gparted, shows proper from fdiskRearrange partitions in gparted to extend a partitionUnable to extend partition even though unallocated space is next to it using GPartedAllocate free space to root partitiongparted: how to merge unallocated space with a partition

                                Marilyn Monroe Ny fiainany manokana | Jereo koa | Meny fitetezanafanitarana azy.