More from The History of the Web
A home online is about as essential as it gets. But we need to make that easier. Where are we heading to build this new web together? The post Our Online Homes Need Infastructure appeared first on The History of the Web.
The earliest work with selling things online was all about reaching a shopping public ready to log on and start. But along the way, they found a whole new audience for shopping, which changed the way we think about commerce on the web.. The post Expanding Access: The History of Ecommerce Part 1 appeared first on The History of the Web.
When we think about AI, we can't only think of what it has generated. We need to think about what it does to what the world has already created. The post What happens to what we’ve already created? appeared first on The History of the Web.
The breakthroughs of the web are often compared to the printing press. But could the former exist without the latter? The post Would the internet exist today if the printing press didn’t come before it? appeared first on The History of the Web.
More in programming
When OpenAI released GPT-4 back in March 2023, they kickstarted the AI revolution. The consensus online was that front-end development jobs would be totally eliminated within a year or two.Well, it’s been more than two years since then, and I thought it was worth revisiting some of those early predictions, and seeing if we can glean any insights about where things are headed.
I like to try different apps. What makes trying different apps incredible is a layer of interoperability — standardized protocols, data formats, etc. When I can bring my data from one app to another, that’s cool. Cool apps are interoperable. They work with my data, rather than own it. For example, the other day I was itching to try a new RSS reader. I’ve used Reeder (Classic) for ages. But every once in a while I like to try something different. This is super easy because lots of clients support syncing to Feedbin. It’s worth pointing out: Feedbin has their own app. But they don’t force you to use it. You’re free to use any RSS client you want that supports their service. So all I have to do is download a new RSS client, login to Feedbin, and boom! An experience of my data in a totally different app from a totally different developer. That’s amazing! And you know how long it took? Seconds. No data export. No account migration. Doing stuff with my blog is similar. If I want to try a different authoring experience, all my posts are just plain-text markdown files on disk. Any app that can operate on plain-text files is a potential new app to try. No shade on them, but this why I personally don’t use apps like Bear. Don’t get me wrong, I love so much about Bear. But it wants to keep your data in its own own proprietary, note-keeping safe. You can’t just open your notes in Bear in another app. Importing is required. But there’s a big difference between apps that import (i.e. copy) your existing data and ones that interoperably work with it. Email can also be this way. I use Gmail, which supports IMAP, so I can open my mail in lots of different clients — and believe me, I've tried a lot of email clients over the years. Sparrow Mailbox Spark Outlook Gmail (desktop web, mobile app) Apple Mail Airmail This is why I don’t use un-standardized email features because I know I can’t take them with me. It’s also why I haven’t tried email providers like HEY! Because they don't support open protocols so I can’t swap clients when I want. My email is a dataset, and I want to be able to access it with any existing or future client. I don't want to be stuck with the same application for interfacing with my data forever (and have it tied to a company). I love this way of digital life, where you can easily explore different experiences of your data. I wish it was relevant to other areas of my digital life. I wish I could: Download a different app to view/experience my photos Download a different app to view/experience my music Download a different app to view/read my digital books In a world like this, applications would compete on an experience of my data, rather than on owning it. The world’s a big place. The entire world doesn’t need one singular photo experience to Rule Them All. Let’s have experiences that are as unique and varied as us. Email · Mastodon · Bluesky
After I put up a post about a Python gotcha, someone remarked that "there are very few interpreted languages in common usage," and that they "wish Python was more widely recognized as a compiled language." This got me thinking: what is the distinction between a compiled or interpreted language? I was pretty sure that I do think Python is interpreted[1], but how would I draw that distinction cleanly? On the surface level, it seems like the distinction between compiled and interpreted languages is obvious: compiled languages have a compiler, and interpreted languages have an interpreter. We typically call Java a compiled language and Python an interpreted language. But on the inside, Java has an interpreter and Python has a compiler. What's going on? What's an interpreter? What's a compiler? A compiler takes code written in one programming language and turns it into a runnable thing. It's common for this to be machine code in an executable program, but it can also by bytecode for VM or assembly language. On the other hand, an interpreter directly takes a program and runs it. It doesn't require any pre-compilation to do so, and can apply a variety of techniques to achieve this (even a compiler). That's where the distinction really lies: what you end up running. An interpeter runs your program, while a compiler produces something that can run later[2] (or right now, if it's in an interpreter). Compiled or interpreted languages A compiled language is one that uses a compiler, and an interpreted language uses an interpreter. Except... many languages[3] use both. Let's look at Java. It has a compiler, which you feed Java source code into and you get out an artifact that you can't run directly. No, you have to feed that into the Java virtual machine, which then interprets the bytecode and runs it. So the entire Java stack seems to have both a compiler and an interpreter. But it's the usage, that you have to pre-compile it, that makes it a compiled language. And similarly is Python[4]. It has an interpreter, which you feed Python source code into and it runs the program. But on the inside, it has a compiler. That compiler takes the source code, turns it into Python bytecode, and then feeds that into the Python virtual machine. So, just like Java, it goes from code to bytecode (which is even written to the disk, usually) and bytecode to VM, which then runs it. And here again we see the usage, where you don't pre-compile anything, you just run it. That's the difference. And that's why Python is an interpreted language with a compiler! And... so what? Ultimately, why does it matter? If I can do cargo run and get my Rust program running the same as if I did python main.py, don't they feel the same? On the surface level, they do, and that's because it's a really nice interface so we've adopted it for many interactions! But underneath it, you see the differences peeping out from the compiled or interpreted nature. When you run a Python program, it will run until it encounters an error, even if there's malformed syntax! As long as it doesn't need to load that malformed syntax, you're able to start running. But if you cargo run a Rust program, it won't run at all if it encounters an error in the compilation step! It has to run the entire compilation process before the program will start at all. The difference in approaches runs pretty deep into the feel of an entire toolchain. That's where it matters, because it is one of the fundamental choices that everything else is built around. The words here are ultimately arbitrary. But they tell us a lot about the language and tools we're using. * * * Thank you to Adam for feedback on a draft of this post. It is worth occasionally challenging your own beliefs and assumptions! It's how you grow, and how you figure out when you are actually wrong. ↩ This feels like it rhymes with async functions in Python. Invoking a regular function runs it immediately, while invoking an async function creates something which can run later. ↩ And it doesn't even apply at the language level, because you could write an interpreter for C++ or a compiler for Hurl, not that you'd want to, but we're going to gloss over that distinction here and just keep calling them "compiled/interpreted languages." It's how we talk about it already, and it's not that confusing. ↩ Here, I'm talking about the standard CPython implementation. Others will differ in their details. ↩