6 ms·
> There's something more constricting about there being one function to bootstrap everything than there is about one file. As a compiler author, there are a bu
by ekidd 3y ago
> There's something more constricting about there being one function to bootstrap everything than there is about one file.
As a compiler author, there are a bunch of nasty surprises to this approach. If you execute a file line-by-line, then functions only exist once you "reach" them.
If you write:
def a(): b()
a()
def b(): ...
...then a() needs to crash when first called, because b() hasn't been declared yet. So your functions need to be invoked via some kind of table, and can't easily use jumps to hard-coded offsets. And b() can't be inlined.
There are dozens of these problems that come up when generating efficient code. And the easiest way to fix them all is to make your entire program "exist" from the beginning, so it can be compiled and optimized as a whole. Which is how you wind up with main().
- noduerme 3y agoThat certainly makes sense, as far as main() goes, but having main() in C++ for example doesn't solve the problem of needing to define functions prior to calls to them. It just helps you put all your stuff before main(), but even then it only "exists" if it shows up in the right order in every previous header file. Line-based stuff like BASIC's GOTO/GOSUB was kind of a fun workaround to the idea of even having functions at all, and I'd happily live in that place still... but... as somoene who manifestly does not write compilers, is it still an extravagant demand in this day and age to ask a compiler to check and include/throw for all the functions out-of-order before running a code file from the top? [edit] What I mean is, this was fundamental to ES3/4 bytecode compilers for VMs like Java or Flash, and it would be absurd to ask e.g. Javascript coders [edit: said Python, don't work with Python, there are cases in PHP where it's necessary] to order their functions in the order they're invoked with virtuals to place them. This is like providing toilets on a cruise ship. It's barely even a "service", like whereas garbage collection or something is an actual service. Restructuring the order of function definitions as you build out dependencies has got to be one of the worst wastes of coder time I can think of. Great if you really can find an optimization by doing that, but the way people code these days that basically never happens. We have to assume that everything we write gets compiled anyway, or why else is it in the code! If there are no dead branches, what's the purpose of not "existing"/let's say pre-virtualizing all the branches, regardless of which order they're written in? (Serious question).
- noduerme 3y agoHey just on a completely off-topic thing, I like your style. But I typed the name of your website into the URL bar, and even stupid Firefox just hung trying to load or trying to redirect from what it thinks should be the default https version. Had to specify http:// http:// to load it. The browsers are making it almost impossible these days to just go to a plain website. half the time they loop themselves into a frenzy and cache the failed address with predictive type to the https version somewhere a normal user can't clear it, even when clearing history. It's a bloody mess for anyone who still needs to build http services.
- tw37074462 3y ago> even stupid Firefox just hung trying to load or trying to redirect from what it thinks should be the default https version Cannot reproduce. The only problem(s) I'm seeing are related to operator error; nothing to do with browsers "loop[ing] themselves into a frenzy". The server at www.randomhacks.net works, but the server at randomhacks.net, on the other hand (and which is not the same as www.randomhacks.net), is for whatever reason failing to respond to the HTTP request. Reasonable guess: it's not a Web server. At best, the service operator has the server (arguably) misconfigured, and the client operator is expecting the browser to do something it shouldn't while blaming failure on the browser after assuming it's doing something that it isn't actually doing.
- noduerme 3y agoYou're right, my bad, the www subdomain just works, the plain domain hangs not as a result of a redirect. I thought I was looking at one of those 443>80 crack-ups once I got it to resolve and it was plain http, but I didn't notice I'd re-added the www.
- ekidd 3y ago> The server at www.randomhacks.net works, but the server at randomhacks.net, on the other hand (and which is not the same as www.randomhacks.net), is for whatever reason failing to respond to the HTTP request. Reasonable guess: it's not a Web server. Yes, the entire setup is ancient. The www site is a static using CloudFlare, which (IIRC) needed a CNAME at the time, and CNAMEs did not work nicely with "bare" domains. The bare domain pointed to an actual server which did stuff, including serving a redirect on port 443. But that server is gone now. I could fix this but it's way down the list after several major home projects. Besides, I come from an era where it was assumed that the www host was a dedicated machine. ;-)
- moron4hire 3y agoTop-level execution doesn't require linear execution. As an example, JavaScript has top-level execution where function definition order doesn't matter. This is achieved by "hoisting" all function declarations within a block of execution to the beginning of the block before then exercising any statements.
- noduerme 3y agoRight. Adding virtual classes in weird orders does not make code more readable, and it's just a hint for the compiler anyway.
- krisoft 3y ago> ...then a() needs to crash when first called, because b() hasn't been declared yet. Why would it “need to” crash? If it is easier to implement to not crash and the developer intention is clear why would you define your new programing language such that it “needs to crash” in this situation? It is as if you go to your garden to pick tomatoes, but you trip over a rake you intentionally put in your way and then as you lay on the ground hurting you conclude that it is impossible to pick tomatoes. Picking the tomatoes in this case is making a compiled programing language which has a main file instead of a main function. And the rake you trip over is the intentional decision to make the program crash in this situation. Just don’t put the rake there (choose to not crash in this situation) and then you can pick the tomatoes (have a compiled language with a main file instead if a main function). There might be more complicated reasons why it is neccesary to have a main function, but this example does not really demonstrate it for me.
- ufo 3y agoOne corner case is that b() might use variables that are initialized further down in the file. Some languages, such as Javascript, lift function definitions to the top so you can call functions defined below you, but it's harder to do the same for variables. In a compiled language it should be possible to detect this at compile time, but it's fiddly and more complicated than having a main function.
- noduerme 3y agoFrom Mozilla's docs: >> JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables, classes, or imports to the top of their scope, prior to execution of the code. >> Hoisting is not a term normatively defined in the ECMAScript specification. The spec does define a group of declarations as HoistableDeclaration, but this only includes function, function*, async function, and async function* declarations. Hoisting is often considered a feature of var declarations as well, although in a different way. In colloquial terms, any of the following behaviors may be regarded as hoisting: >> Being able to use a variable's value in its scope before the line it is declared. ("Value hoisting") >> Being able to reference a variable in its scope before the line it is declared, without throwing a ReferenceError, but the value is always undefined. ("Declaration hoisting") >> The declaration of the variable causes behavior changes in its scope before the line in which it is declared. >> The side effects of a declaration are produced before evaluating the rest of the code that contains it. So basically all the shit we take for granted when not writing C/C++. What is curious to me is whether the main reasons for not attempting this in a C++ compiler in 2023, or else moving the language spec in this (unofficial) direction, is to produce maximal performance-optimization, or if it's mostly a cultural thing at this point. It does have the benefit of turning away hordes of javascript kiddies from the gates, but, the relative value of the performance edge to any optimization is getting weaker as compute becomes cheaper.
- Kim_Bruning 3y agoHeh, I first ran into this issue with the built in assembler in BBC BASIC II. You couldn't naively make a forward reference to label. This is because wasn't defined yet at the time the assembler encountered your instruction. That's when you learned about multi-pass assembly.
- em-bee 3y agohow about before anything is executed, add a parse step that reads the whole file, looks for function definitions, and then goes back to the start to execute?
- chriswarbo 3y agoWhat counts as a function definition? def a(): b() a() import random with open("max", "r") as f: m = int(f.read()) b = (lambda: "foo") if int(input("Pick a number: ")) % m > random.randint(0, m) else None
- deleted 3y ago[deleted]
- em-bee 3y agofair point, but this is why you need multiple parse steps. first parse you get the overall structure and note where forward references are made to things that are not known yet. in the second step you fill in those references as found. it becomes problematic if a function definition is conditional. i suppose then that the compilation should fail because i guess conditional definitions would not be covered.
- wongarsu 3y agoJavascript solves this with function hoisting. In simplified terms you do two compiler passes, once for global symbols and once for linear execution. After all nothing stops you from writing in your language definition that defining a function anywhere in the file is the same as defining it in the beginning, and then you can treat it as if the entire file was in a main function, except for functions and the declaration of global variables.
- cryptonector 3y agoDoesn't have to be that way. You can just do two passes.