The days of sweeping declarations regarding obviously periodic trends have never arrived.
I've been around long enough that "safe" gave way to "productivity" and back to "safe". There's kind of a nascent ethos of being "better" in each new generation that just results in these pendulum effects.
The overall effect seems to be enormously positive. I can now bounce between several completely valid build environments, ecosystems, and languages for a given project depending on what is required. But make no mistake. Our kids will probably look at us like we're crazy as they embrace the 2040 equivalent of JavaScript and Python again.
Regardless of the cycles in the computer industry, I would never consider a dynamically typed language for large projects ever again.
I’ve been there, done that, and worked most of my career in dynamic languages. There’s just better tools available today. There’s no going back for me.
Python with types or TypeScript is as dynamic as I’m willing to go now, and only as a last resort.
My guess is he’s referring to the way that types are fundamentally optional no-op statements in python, and therefore the level of “typing” in a given project is necessarily opinion-driven and can only be enforced through building up a lot of tooling, like making sure a type checker passes or fails all code going into deployment or CI. And even in the best case, types are duct-taped on, so there is no such thing as “perfectly type-safe”
So as soon as you have two developers on one project, you have two different opinions about it.
Is this the case here too though? My impression was that dynamic languages grew popular because of deficiencies in static type systems, making it hard to express things while requiring a lot of boilerplate and not providing enough runtime safety (e.g. NullPointerException), and a faster feedback cycle, as you need a compile step and need the entire program to be free of type errors. For the first point, type systems have been improving in these regards, and for the second you get instant feedback in statically typed languages without needing to even run anything. Some languages like Roc even let you run code while there are type errors in other code paths.
I have no working crystal ball, so I don't know. But I don't see any obvious reason to think it isn't.
If history is any guide, then this is just the latest cycle, and the new hotness will become dynamic again.
Your list of improvements is correct, but I'll just point out that with every cycle, a similar list of improvements is cited as the reason why whatever the fashion of the day is will become The One True Way. So far, such expectations have never been fulfilled.
I think the article argues for "gradual typing" being somewhere in between but being strictly superior to dynamic typing, to the extent that we may never see the pendulum swing back to purely dynamic typing again. (It is my view that obviously static types aren't going anywhere, and that obviously the pendulum will continue to swing back and forth there; I don't think the article contradicts that either.)
Instead of worrying about types, why not worry about the actual code quality?
Half of all typescript I've seen uses "any", not to mention the fact that it obsfuscates what's actually running in the browser and forces an unnecessary build step for things that aren't "web apps".
> Instead of worrying about types, why not worry about the actual code quality?
I'd argue that a sign of good code quality is using types even in languages and contexts where you don't have to.
PHP is technically still a duck-typed language, but the community has embraced its relatively new strict typing features with open arms and the PHP ecosystem is all the much better for it.
I'm half with you. I think TS is only worthwhile in strict mode, as soon as an "any" creeps in all bets regarding safety are off. Same story with trusting values returned from 3rd-party libs - everything needs validation.
But you talk about code quality... Honestly if I've got a tricky task the first thing I'll do now is write the types for it, they'll keep me on the right path.
Example: Next week's job is to add analytics to a codebase (I get all the glamorous tasks - well, actually just all the tasks), and the geniuses with the spreadsheets have come up with like 100 different events to track, each with a selection of sometimes-overlapping properties.
I've done this before in plain JS and it was unpleasant. In TS once I have the types nailed down the rest is easy - and when they inevitably change their minds about something the week after next I just alter the types to match and then follow the errors until it works again.
You're saying that half of the projects you've seen successfully adopted strict typing? And others use an occasional escape hatch, but still try to introduce reasonable typing? That sounds like a success story to me.
Because it gets exponentially harder to reason about untyped codebases the larger they get. "Code quality" is not good enough, there's no way to enforce that. You can statically enforce types, and use linting rules to discourage usage of constructs like "any".
I wrote my first typescript this morning. I was trying to do something weird in React Native, which I've also never used before. I was getting red lines all over my editor. Saved. It hot reloaded anyway and ran the code and such. The errors I was getting were pretty inscrutable. I think that's the nature of untagged unions maybe? Anyways, it didn't actually put up the hard wall I'd expect a type system to do, and with that I wasn't in a dialogue with the compiler to get the types working and thus the program.
The whole point of static types (well one big reason at least) is to improve the actual code quality.
I don't understand how you think it obfuscates what is actually running in the browser.
Nearly all non-trivial web projects have a build step even if they aren't "web apps". But I agree it would be nice to at least have the option to avoid it. There is a JavaScript proposal going through that should fix that.
> The whole point of static types (well one big reason at least) is to improve the actual code quality.
I have worked on multiple typescript projects that had terrible code quality. Types do not make you write SOLID code.
I find functional programming and well-used functional patterns do result in higher quality code. Typescript’s type system makes writing functional code more difficult. The documentation even recommends against it[1].
IMO typescript is easy to prescribe as a panacea, “just use typescript”, whereas understanding how to write SOLID code takes time.
My world changed when I started thinking in a strongly typed way (not just using string and number) and representing state changes as different types rather than interpreting than through property values. Once you do that then your code becomes mapping from one type to the next.
For example, if `type ShoppingCart = EmptyCart | LoadedCart` then `addToCart` is just a map from `ShoppingCart` to `LoadedCart`. It makes invalid states impossible to represent and flows become clearer. Add in good FP and composition becomes easier.
I am not against types but I do find typescript’s type system to be deficient. Additionally, functional programming is not incompatible with type systems but typescript’s type system in particular makes it more difficult.
Several of the terrible typescript projects I referred to still used property values to represent state (like your example). Just because every definition has a type doesn’t make it good code. Shitty typed code is still shitty code. My concern is that many in our industry conflate typescript with quality and stop there.
I'm curious which part you find deficient? It's biggest downside is probably being Turing complete but that doesn't make it deficient, rather it's too easy for devs to code incomprehensible types with it.
I agree, I’ll take JavaScript over TypeScript any day. I work on massive codebases and have never had bug related to type safety, or any issues scaling.
It’s disappointing that a lot of arguments for typing fail to explore why untyped languages became popular to begin with and how those benefits can be maintained throughout the migration process through partial typing To complete typing.
When typing is applied gradually throughout a codebase it can sometimes manifest as the worst of both world and a complete argument should at least acknowledge that as well as the impact of bad typing on codebases.
What are the downsides of gradual typing on a codebase? I've never worked with it, but watched some talks on it and it really sounds promising. I understand the downsides for compiler complexity and for performance, but not on the codebase itself.
- Worse type error messages, as the type system has to be more complicated to handle the sorts of patterns that are common in untyped code.
- You can still get type errors at runtime in your typed code, if it interacts with untyped code, because it isn't feasible to validate all types on the boundary. You're only guaranteed no runtime type errors if all of your code is typed.
- The migration path from untyped to typed isn't always easy. Depending on how your code is organized, it's possible to have correct untyped code such that there do not exist type annotations you could add to it that would make it type check.
For one thing: because as soon as some piece of data leaves the typed world, all of your guarantees about its integrity go away. This is, in some sense, even worse than a situation with no types at all - in that case, you have no guarantees, which is better than having misleading ones!
If types are to data flow what structured programming is to control flow, it's a bit like being able to call into unsafe functions that can corrupt your stack. You could waste hours trying to trace the flow of execution and being completely stumped by your code's behaviour, looking at stack traces that make no sense...
Furthering that analogy, like how a structured programming language restricts control flow to specific structures as compared to free-form branches and jumps, certain interfaces and patterns that you can get away with in a dynamic context can't be expressed (or expressed cleanly) in a statically typed language. Just as your average Java programmer doesn't usually feel constricted by the inability to write Duff's Device in their language of choice, once you get good at TypeScript you rarely feel inclined to construct dynamic interfaces, but JS developers...a world where static typing isn't universally enforced, especially if you're working with a bunch of JS devs who don't fully embrace static typing, encourages the construction of difficult-to-type APIs. This then feeds back into the first issue: reasoning about type integrity when using these APIs becomes painfully difficult.
It's not that the general idea of "gradual typing" is bad, but that strong types become a leaky abstraction in practice. If you have to constantly fight against the weakly typed nature of the underlying language, that defeats the point.
> The problem is not as simple as taking the ECMAScript grammar and augmenting it with type annotations. There's a reason that Microsoft (TypeScript, Safe TypeScript), Google (AtScript, SoundScript), and Facebook (Flow) have all collectively attempted this problem and came up short.
Types are ultimately a contract. If your code was not originally designed with these contracts in mind and then you introduce a system that actually promotes ad hoc interfaces (TypeScript or any structurally typed system) then what you get is a mess. You're constantly Pick or Omit-ting everywhere. But worse, you absolutely have to use "any" or "ts-ignore" during the process. You can't avoid it. But one single "any" has the effect of stripping all code of type annotations, making the entire process a giant waste of time.
To compound matters, none of the TypeScript devs I've worked with have any experience with type systems. They don't think in terms of interfaces. They are still ball-of-mud developers. They did not come from Java or C/C++ or even Haskell. They came from Python or Ruby.
I'd also caution people about using third party types (i.e. DefinitelyTyped). These are often not correct because the underlying library is not in TS and does not have type information. You will pull your hair out when the library does not match the type definitions. These third party definitions can introduce bugs into your code. They can falsely claim that some field exists on an object which, in fact, does not. Your IDE will happily autocomplete to the invalid field, TS will happily compile it, and your JS run-time will unhappily crash.
Done badly you can end up doing a lot of admin to make the types work without actually getting the benefit of that type safety. Done well you can get the benefits of type safety where it really counts and avoid the overhead where it doesn’t.
> What are the downsides of gradual typing on a codebase?
Typing complex business domains and interactions is hard. Most developers don’t have a lot of experience with it or the time to do it properly as they produce features. It doesn’t help that many developers start their career with untyped languages and transition into typed languages without learning it properly.
Typescript is a great example because a lot of frontend developers may have only ever worked in JavaScript and have absolutely no foundation to build on but trial and error on your companies production codebase.
It's definitely not that the developers are inexperienced with types. You're sort of making a "white man's burden" argument. Very few web developers are just writing javascript at work.
It's simply that you can't paint over a weakly typed language with strong types without causing all kinds of crazy edge cases. They're fundamentally different paradigms.
YES YES YES. I'm witnessing this nightmare with a project that started out as untyped and now we're adding mypy to it because without typing it is difficult to understand and work on. 2 million lines of untyped python.
It's basically a huge technical debt and I doubt we'll ever get to the point where we can enforce this in CI
it's worst of both worlds because types are not free. There is a certain amount of energy and effort and maintenance that you must put into type annotations. Before you reach the point of return on that investment you have to plow through the period of limbo where the cost of annotations is greater than the rewards. Some codebases never make it out of that morass.
One could easily make the argument that adding types to a preexisting codebase is more difficult than adding them to a greenfield project. So the effort and energy (and cost) is even higher.
Let's just say, you better be snuffing out an absolute fuckton of null reference and other bugs that a type system can actually help with for it to be worth it.
> Before you reach the point of return on that investment you have to plow through the period of limbo where the cost of annotations is greater than the rewards. Some codebases never make it out of that morass.
I disagree. In my experience of adding types to a terrible Python codebase the rewards are always greater than the cost, even if the effort is frustratingly high. In that situation the biggest rewards are that you make the code understandable, navigable and maintainable.
The frustrating effort must be paid whether or not you add static types. You can either pay it again and again over many years of people trying to figure out how the hell the code works and wasting time navigating and refactoring the slow way, or you pay it once up front and be done with it.
The only situation I can think of where it might not be worth it is if you have a codebase that is marked for death. If it's being replaced then.. eh. Leave it and let the problem solve itself. Otherwise I've found the effort to always be worth it.
The only big issue I've found is convincing colleagues of this. Especially colleagues that use Vim or Emacs and don't get half of the benefits of static types.
> Before you reach the point of return on that investment you have to plow through the period of limbo where the cost of annotations is greater than the rewards.
I'm a staunch supporter of static typing. But man, the amount of energy people put into getting things like mypy to go green in strict mode just doesn't make sense to me. There are going to be situations where the cost to avoid the mypy ignore on a line will *never* be worth the long term benefit. But nevertheless they persist
Types slow you down. New work is first completed in untyped languages. People start using the work. People complain there aren't types. Types are added. Work is now slow in the language. New work is now done in another language without types.
“Types slow you down” is the _stupidest_ excuse I hear all the time.
As if developers of untyped languages don’t spend ungodly amounts of time pretending types don’t exist, but needing to manually check them everywhere, wonder why shit blows up at runtime, litter their code with “typeof” style checks, litter their tests with type checking.
The types exist and need to be considered whether you believe it or not. Might as well let the computer help you out.
There are maybe some programs where "time to first run" is a critical metric. But where I sit we spend way way way way more time living with a program after it has already been written. This means maintenance, bugfixes, and refactors.
Even if what you say is true, I'll trade some initial coding time to buy more efficient maintenance.
I dunno, I think the productivity promises of dynamic typing have been conclusively disproven, so maybe next time people will be able to at least say "we know that isn't a good idea".
Maybe there is an argument there for non-programmers in technical fields, that use programming at their jobs, but it isn't their primary job. Like a data scientist or architect, trying to use something convenient and easy. The problem is, that usually it catches up with them (and with bigger programs), in terms of poor quality code and bad habits. The argument then becomes if they should have learned better practices and habits in the first place. Sometimes what seems like a shortcut, is not really so.
that might have been true in the 2000s, but it doesn't apply to modern languages with things like generics, ADTs, type inference, null safety, etc.
you know what really slows me down? trying to use a function in a dynamic language, and having no god damned clue what type of arguments it accepts, and having to figure it out by grepping through the code or dynamically instrumenting a running program.
I think its more along the lines of things are prototyped without types, the proof of concept mostly works, then people realize that types are needed to reduce bugs, improve speed, and create a maintainable base as the project grows. What people should do is rewrite from scratch using the prototype as a vague guide, but instead people try to desperately fix the prototype incrementally. Its not the types that makes things slow, its the size of the codebase, and the lack of expectations on quality and performance.
Programming seems to be settling down in this area. Parameters to functions and fields in data structures are usually explicitly typed, while local variable types are inferred when possible. C++, Go, and Rust have all converged on this.
C++ used to suffer from "for" loops with insanely long type declarations for iterator variables. "auto" fixed that.
Inter-function type inference, while technically possible, is just too confusing for people reading the code. So that went away. Mostly, type inference is now forward only. Inverse type inference through long chains is, again, possible but too confusing.
Explicit typing of structure fields and function parameters allows automatic generation of reasonably useful documentation. That gives programmers anchor points at which they can see types.
So this has become a solved problem for compiled languages.
Disappointed to find a puff-piece on typescript. Dishonest headline.
Javascript frustrates me just as much as the grumpy old man in the article. That said, I once sat down and asked myself, "self, why was it okay to live through the php years yet you despise javascript for being the same way?" And then it dawned on me, my involvement in php projects forced me to have a low-level understanding of the language that I never acquired with javascript.
The consequence for me is that javascript is still full of voodoo and dark magic, all very frustrating and bowel irritating. But that's not the fault of the language, that's the fault of the knucklehead trying to use it without really digging into the internals and understanding how it should be used. That would be me.
Not learning how javascript internals work and complaining about javascript is no different than when Mongo first came out, and folks shoved third normal form schemas in there and complained loudly that Mongo was a lousy RDBMS. It's not an RDBMS, mate.
If anything this article instead implies that typescript means you don't have to bother learning javascript internals. Do not recommend.
JS core (that's worth knowing) is pretty simple. My mental model is basically there are primitive types, arrays [], objects {}, and Promises. After that, you basically just have to understand the event loop and you're good to go. Then there's other special things like async/await, spread operator, etc. Among programming languages, it doesn't have THAT many things to learn at its core.
The correct title is “TypeScript and the dawn of gradual types”
HN Guidelines: “If the title includes the name of the site, please take it out, because the site name will be displayed after the link.
If the title contains a gratuitous number or number + adjective, we'd appreciate it if you'd crop it. E.g. translate "10 Ways To Do X" to "How To Do X," and "14 Amazing Ys" to "Ys." Exception: when the number is meaningful, e.g. "The 5 Platonic Solids."
Otherwise please use the original title, unless it is misleading or linkbait; don't editorialize.”
Can we just agree that there can never be one solution that fits all problem spaces. I use both C++ and ruby for different jobs and I like/hate both equally.
This is a soapbox I've been on for decades. There's a reason why I have bothered to become competent in a large number of languages: each has their own strengths and weaknesses, and so there is no single language that is best for every sort of program and environment.
I came to typescript after many years of C++. I found typescript to be a much better language than C++ overall, and I'm far much more productive with typescript.
I'm glad that a lot of people can manage without the types, and I've seen many successful big projects plowing along just nicely.
I personally wouldn't be able to maintain a large project without types. It seems that a lot of people figured out for themselves how to do it. If you are one of them, how do you refactor the codebase? Are you relying solely on unit tests to avoid breaking all involved pieces? In Typescript I usually just go ahead and change the structure or method parameters in type-incompatible way. In many cases it's sufficient to fix all places to maintain the project in an unbroken state.
I'm looking forward to the launch of Zig, that should be a good choice for WASM. Only if I could get a pytorch-like interface in Zig now...
I hate TypeScript so much it's unreal. A MS trojan horse to try and own the full stack, I hope you'll all be happy when we won't be able to use any of our tools without complying to corporate linguistic standards and watching the mandatory 20m of commercials per code scope.
Naivety of people in software development is something else. Billion dollar corporation hired 10 token nonbinary people and people just forgot, if they ever knew the history.
One useful thing I’ve found with typed languages is that I end up implementing the entire specification for a program in the type system even before writing a single line of actual working code.
Makes it easy to fix and refactor things early on and improve things from a developer experience and interface perspective.
I push implementing a function as far out as possible, when the entire structure of the program becomes clear.
This hack easily makes me 10x more productive. Plus I don’t share the same annoyances with types and TypeScript for example that other devs face. Once it’s set up (just adding a tsconfig file and a package file) the type system just sort of disappears — I mean, I rarely fight with it.
I do agree though that most of the complaints with these systems, languages, and tools really come from the vast amount of competing “getting started” and build guides that always seem to get out of date or use some radical new way of doing things that upsets the whole ecosystem. There have been so many changes in this regard. That, I will say, I don’t have an answer for.
Ruby on Rails? I've built apps that have been running for years in a couple of weeks. If you have a very logical structure, the types take care of themselves.
Huh. I've been doing JSDoc typing, described halfway into TFA, for 2-3 years now but I didn't know it had a name or was considered a thing. Generally I've been really happy with it - no transpilation step to think about, and I get almost all the type hints and errors/warning I'd get from writing TS. And for very little verbosity - I probably only have 2-3 JSDoc comments (that declare types) in each typical .js file.
The main drawback I've fought with is that when you're doing something complicated - e.g. extending or decorating a module imported from elsewhere - it can be hairy to convince the editor to infer what's happening. The other one is I've never found a good way to author an event emitter, such that you get inference and type checks on code subscribing to the events. But there could be solutions to both points that I've been missing.
Inference for static types requires more from the compiler in two key ways that impact the developer experience. First, it's just plain more work to do when compiling, so compile times are longer than they might otherwise be. Second, error handling and messaging needs to be written very carefully to avoid dense and unhelpful output when inference fails. It's positive in many ways, but it's not a free lunch.
Static typing can have advantages but that doesn't mean it's completely invalid to use a dynamic or untyped language. It's understandable if some people prefer not to be involved in those projects though.
But it's completely feasible to use dynamic languages for non-trivial applications. I think it's fair to say that Hacker News is not a trivial application and it's written in a Lisp dialect called Arc.
The biggest advantage of dynamic languages is probably that they are usually more concise. Which can lend itself to a more elegant expression of intent.
Another advantage might be more flexibility reducing the tendency to add boilerplate or a lot of schema-specific code. And I am aware that many people consider a lack of schemas to be the worst thing ever. But at least they are flexible.
And yes I am aware that static types can eliminate errors at compile time. Those types of advantages don't completely invalidate the use of untyped languages.
Agree with the sentiment (statically-typed languages are cool), but TS is not ideal. Is the best we have if you want something JS-like, but try to explain the following monstrosity to a junior colleague who's starting with TS in the context of web applications (using one of the most popular frameworks out there, NestJS):
// a DTO that handles the creation of some kind of resource
...
@IsArray()
@ArrayMinSize(1)
@IsString({ each: true })
@ApiProperty({
example: ['software', 'maths'],
})
tags: string[]
That's real code. Since the TS types gets erased when the code is transpiled to JS, one has to annotate the whole thing just to be sure the clients are not sending us invalid data. And the validation via annotations couldn't be more cumbersome. 90% of the code in the DTO file is annotations. Reminds me Java from 10 years ago.
The biggest problem with most typed languages is string handling, especially null terminated strings. Returning a string from a function is a nightmare in almost every typed language, except Delphi/Free Pascal, which does auto-reference counting, and manages it all, you never have to allocate/free memory for them, and they can hold gigabytes.
Typed languages offer some efficiencies, and can, if properly used, help prevent entire classes of footguns, but they do require a bit of planning. I've always wished I could do the same "gradual type" thing with Pascal, Basic, etc. As the program is run, the types are checked, and slowly baked in automatically.
> Returning a string from a function is a nightmare in almost every typed language, except Delphi/Free Pascal, which does auto-reference counting, and manages it all, you never have to allocate/free memory for them, and they can hold gigabytes.
Why mention memory allocation at all? There are plenty of typed languages that have automatic garbage collection and handle strings just fine.
Go (Golang) comes to mind as a superb example of a typed language in which string handling is a breeze.
I'm so confused. What do you think happens differently in C#/python/Ruby/rust/whatever when you add one string to another? Or when you read into a buffer without a predefined size? Or assign one string reference to two variables?
JavaScript, Python, PHP, Ruby etc fill a niche. Personally I love strongly typed languages, but I get why people don't want to deal with it. I am old school and do not use an IDE, so for me strong typing is a must.
> Honest questions: What do you consider an IDE? Do you use syntax highlighting?
I use GVIM, no plugins. syntax highlighting is fine and file browser too, but once you start getting into autocomplete and plugins that too much I think. the IDE should not be a replacement for a poorly designed language, and that's what they have become I think.
> I am old school and do not use an IDE, so for me strong typing is a must.
I, too, prefer to avoid using an IDE. I appreciate strong typing, but I certainly don't feel that loosely or untyped languages are made more difficult to use by not using an IDE.
Oh, sure, I completely understand where you're coming from. But if I'm using an untyped language, I'm already having to keep that sort of state in my head regardless.
Biggest reason for the success of TypeScript is it aids IDEs in statically analyzing your code and providing enhanced autocompletion results like e.g. methods and properties. In dynamically typed languages this a much more difficult task and can only be approximated by applying some heuristics without actually executing your code.
This is definitely an advantage! No dispute here. But whether static types make programs safer and their architecture cleaner is something in need to be proven empirically. And as others already wrote: There is a reason why dynamic scripting languages became popular.
Arguably C is losely typed rather than strictly typed. int for example is some integer type, dont worry about which one, and people keep reinventing this too. Sometimes you want stricter, sometimes more loose, but most languages have a sweetspot where they provide a decent syntax and anything outside it is crap.
The language which solves this will allow people to select the level of type abstraction on a per task basis, while retaining full performance. It will be nice when we get this, but no language is even close.
"Gradual typing" works as a sales pitch, but having had a go at that it, it's at best a way of getting the editor to give better autocompletion. It's only with strict mode on that I feel Typescript is really worth it.
The article also touches on Typescript-in-JSDoc, but that can get really ugly with complex types and there are a few things I just couldn't figure out how to do when I gave it a proper shot last year.
I've been developing all kinds of applications with JavaScript. Some have handled multi-millions of users per day, thousands per second. I started with Netscape 3.0. In all that time there's only been a handful of times that I wish JavaScript was typed and maybe two handfuls of times when the lack of types caused a problem for me or my team.
On a large project, a lot of discipline is needed to make sure typing gets used everywhere.
Even worse, when you have a prototype that morphs into a large enterprise application, someone needs to go back and fill in all the types. This can be a struggle if everyone is gone.
basically this just kicks technical debt down the road.
Ruby sorbet has generally been having slow adoption. Does anyone know how much github is using it internally on their (we know substantial) ruby codebase?
just make javascript support static typing, e.g. let x:number=100 etc, similar to what python does, without a totally new tsc compiler, an eslint for typescript, and all those c# stuff along with it. can we just improve js instead of using ts?
I've been around long enough that "safe" gave way to "productivity" and back to "safe". There's kind of a nascent ethos of being "better" in each new generation that just results in these pendulum effects.
The overall effect seems to be enormously positive. I can now bounce between several completely valid build environments, ecosystems, and languages for a given project depending on what is required. But make no mistake. Our kids will probably look at us like we're crazy as they embrace the 2040 equivalent of JavaScript and Python again.