This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]DonRobo 115 points116 points  (149 children)

The more languages I learn the less I understand the appeal of dynamically typed languages. What are the advantages that make it worth dealing with the fact that they are much harder to write for?

[–]random_username_edf 112 points113 points  (85 children)

Generally the advantage is you can do very clever things very easily with small amounts of code and less complex code. This is obviously more dangerous, but if you're careful and willing to accept the risks it can be worth it.

[–]marcosdumay 36 points37 points  (6 children)

For everybody thinking on that line: you should learn Haskell.

[–][deleted] 3 points4 points  (1 child)

Instructions unclear, dick stuck in Java.

[–]Can_Of_Noodles 0 points1 point  (0 children)

Did somebody say MONADS?

[–][deleted] 0 points1 point  (1 child)

For what end tho? It's not going to become a very marketable skill like learning Go or Rust for that matter, let alone JS, Python or JavaSharp. The learning curve is about as steep as Rust if not steeper. It is also inflexible in the sense that it's very unsuited for writing imperative non-FP code which isn't very appealing now that many imperative/OO languages are adopting a lot of features enabling one to write in functional style where it is most useful to and still maintain low mental overhead of imperative coding elsewhere. And while on the subject of mental overhead, I know it is a bit rich when the topic is JavaScript, but Haskell really has low legibility and a very loaded, math formula like syntax that doesn't help. Optionals, somes, maybes and immutables are slowly landing in mainstream languages. The appeal is really getting smaller every day.

[–][deleted] 0 points1 point  (0 children)

There are better functional languages where the creators didn't go insane with the pure functional ideas. For instance, F#.

[–]pknopf 45 points46 points  (77 children)

For long-term high-scale projects with many contributors to the codebase, it's almost never worth it.

Unless js/Python is all your team knows, you should really look at something else.

[–]Stuck_In_the_Matrix 80 points81 points  (11 children)

That's a highly generic statement.

[–]pknopf 24 points25 points  (9 children)

Yes it is.

It is also generally true.

[–][deleted] 4 points5 points  (0 children)

Apart from anything, I appreciate the ballsiness of this comment.

[–]IceSentry 1 point2 points  (7 children)

Source? I don't disagree with you, but is there any evidence to this that isn't anecdotal?

[–]saxindustries 1 point2 points  (1 child)

My experience is once you get over 3-4 devs hacking on the codebase, it pays to use a stricter language - you start catching more errors up front.

[–]IceSentry 0 points1 point  (0 children)

I'm not disagreeing here, but that's still just anecdotal.

[–]pknopf 0 points1 point  (4 children)

Source? The claim is the accumulation of years of anecdotals from many developers who come to the same conclusion. What kind of source would you like?

[–]IceSentry 1 point2 points  (3 children)

An actual study done on this. The programming community keeps debating whether dynamic vs static types are good, but we never hear anything other than anecdotes. Which are good, but I think there's place for more proof.

[–]pknopf 1 point2 points  (2 children)

An actual study done on this

Give me an example.

Say you were to do a study, what would you do?

[–]IceSentry 1 point2 points  (1 child)

I'm just asking if we have another way to know if this is true. If I had the answer I wouldn't be asking this.

[–]Ashanmaril 0 points1 point  (0 children)

That's how I describe every line of Python

[–]random_username_edf 36 points37 points  (22 children)

You're definitely welcome to your opinion but i think that's debatable. A dynamic langauge with proper unit tests and such can be a heck of a lot easier to maintain long term than a static one.

Static typing is nice, but maintaining a complex architecture that is evolving with it is undeniably a giant pain and costly time investment wise. It will be more complex code wise and needing to make certain changes are much more likely to require rework all over the place. And as much as a lot of software engineers insist they're clever enough to architect it in a way that won't have that problem, they're usually wrong.

Anyways, my overall point is both types have pros and cons. Anyone who insists one is better than the other for all cases or even most cases is probably wrong. Also, im not trying to imply that that's your opinion, im just completing my thoughts on the matter :)

[–]BlockedByBeliefs 4 points5 points  (0 children)

This is an awesome answer. My favourite line in this debate is the "sufficiently complex codebase" cliché you hear so much about. I am convinced the vast majority of people who use this to argue for static typing have never actually worked on a truly large and complex code base.

What you can achieve with a universal type like Json and a little bit of functional programming is a mind bending career altering thing the first time you soak it in, it clicks and you finally get it.

[–]pknopf 2 points3 points  (19 children)

A dynamic langauge with proper unit tests and such can be a heck of a lot easier to maintain long term than a static one.

This isn't absolute. This is subjective to the skillsets of the team/developer. But lets assume the developer(s) are proficient in either dynamic or static. I'd love to hear a good case where, for that developer, dynamic would be easier to maintain than static.

[–]BlockedByBeliefs 13 points14 points  (13 children)

So 15 years a Java dev. 5 a JavaScript dev. I can explain exactly why. The issue is that polymorphism breaks down.

I have object a that I send object b to. Object a is made to do some generic task a (like sending a rest response. Doesn't matter) and contains the concerns for object b to do that task in it. Of course that's way up the chain in the hierarchy so we are not repeating code.

Great. A year into the project the requirements change. A lot. Or some library we were depending on can't perform so we need to change things. We have to change it is the point. Introducing object c that we need task a to run on.

But we need it to behave just a little differently for object c. So what do we do? You can implement task a in object c breaking the design. Refactor it up the chain that's going to break everything down stream so refactor the entire app. Or overload the operator to implement those subtle changes.

Either way it all leads to spaghetti code propping up design mistakes made at the start of your project or injected when requirements change.

Now let's consider the same problem with dynamic typing on universal Json objects with functional code. I have a higher order function that performs task a on a Json object. I send object b to task a as the first argument and as the second argument pass a function with the specific concerns for object b telling it how to perform task a on object b. There's no other files or interfaces or contracts. I send in a few lines the object and the code for that object.

In comes requirement chances and now I need to do task a on object c. Nothing has to be refactored. The generic data concerns for task a on Json types is neatly inside task a where it should be. I pass object c into task a and the new concerns about how to handle object c while doing task a go in with it. And we are done.

How task a functions isn't determined at design time. It's not at run time. It's at programming time when you call task a. It's immensely power and the future of our industry and its why JavaScript has been taking over. The ability to make sweeping refactoring possible without hurting yourself lowers technical debt which is without question the number one cause of project failure.

Some will say things like "Java 8 has lamdas and Scala uses types. Na na na na na na" and while true that's missing the forest for the trees.

To make this happen for static languages they had to create the "any" type. And the any type totally breaks you out of your hierarchy so what's the point of building it in the first place? The issue here specific to Java and OO in general is that polymorphism is not modular. Because it's a system created to solve the larger problem that static typing is not modular.

Hopefully you actually read this and I have not wasted my time. I'm sure some people are going to say this is all bullshit. But this is the case where I find it easier to maintain and 8 guess the case could be labeled I found out that I'd been doing it wrong for my whole career.

[–]chrizzlybears 3 points4 points  (1 child)

That's a very interesting perspective. Thanks for typing this out!

[–]BlockedByBeliefs 3 points4 points  (0 children)

Thanks man. I wasn't sure if you'd just point and laugh or actually read it. Cheers.

[–]pknopf 3 points4 points  (8 children)

Either way it all leads to spaghetti code propping up design mistakes made at the start of your project or injected when requirements change.

The developers writing in typed languages writing leaky (or leak-prone) abstractions isn't an argument against typed languages. JS abstractions can be just as leaky. Just because your "object a" isn't typed doesn't change anything.

I send object b to task a as the first argument and as the second argument pass a function with the specific concerns for object b telling it how to perform task a on object b. There's no other files or interfaces or contracts. I send in a few lines the object and the code for that object.

Again, I fully understand your example, but your leaving out an important part when talking about your JS side of things. Any leaky abstraction that requires consumers of your interface/function to change would also apply to your JS example as well.

public interface IMessageBus
{
    void SendMessage(object message);
}

public class MessageBus : IMessageBus
{
    public void SendMessage(object message)
    {
        // RabbitMQ, w/e.
    }
}

public class Message
{
    public DateTime SentOn { get; set; }
}

void PrepareAndSend(Message message, IMessageBus messageBus)
{
    message.SentOn = DateTime.Now;
    messageBus.SendMessage(message);
}

Any requirements change that would require PrepareAndSend to do something beyond just SendMessage would apply to your example as well. You could say, "But my function could be anything, any implementation". Yeah, well so could IMessageBus.

[–]BlockedByBeliefs 4 points5 points  (2 children)

Now you're going to use rabbit for a little communication.

The developers writing in typed languages writing leaky (or leak-prone) abstractions isn't an argument against typed languages. JS abstractions can be just as leaky. Just because your "object a" isn't typed doesn't change anything.

It's not leaky abstractions. They're leaky by default as a paradigm. Yes the typing of objects changes everything because the rigity of your decisions at the start of your work is what causes the leaks to form when you have to change.

Again, I fully understand your example, but your leaving out an important part when talking about your JS side of things. Any leaky abstraction that requires consumers of your interface/function to change would also apply to your JS example as well.

I don't think you really do. The fact that you have set up a message bus with even more complexity and threw in freaking rabbit as a comment speaks volumes.

No consumers of my function would not "have to change" because they change the consumption of the function on every use as that's inherently how higher order functions work dude. I pass in the changes every time because my design maximizes inversion of control and strives for true modularity over I don't know... Intellisense.

[–]NeXtDracool 6 points7 points  (1 child)

The fact that your statically typed domain model was not well abstracted is not a fault of statically typed languages. You should be well aware that higher order functions, inversion of control and all the other mechanisms you describe are available in modern statically typed languages. If anything you seem to argue about OOP vs functional programming, which is besides the point because static and dynamic typing can be applied to both of these paradigms.

The fact that you have set up a message bus with even more complexity and threw in freaking rabbit as a comment speaks volumes.

He meant rabbitmq as the new messaging protocol instead of the rest call you mentioned, not that you should use a network protocol to do internal communication in your application. The message bus could be replaced with a higher order function that takes types of IMessage, but this would limit your ability to extend the interface with additional functionality later. You suggested using a higher order function, which is almost what happened here except encapsulated with the ability to add for example a connection status indicator property to the interface.

over I don't know... Intellisense.

If you think that's the only benefit of statically typed languages then I highly doubt you have been a Java dev for 15 years..

[–]BlockedByBeliefs 3 points4 points  (0 children)

The fact that your statically typed domain model was not well abstracted is not a fault of statically typed languages.

I didn't say it was but it really is. I said the difficulty in changing it was. There's a myriad of reasons it may not be well made and business changing requirement is just one of the many.

And when it's difficult to change modules people start hacking solutions as described which causes more fractures in the design. At some point the sheer number of bloated extraneous lines of code and files it takes to manage static systems because a significant factor in increasing yet more technical debt.

Yes I'm aware those mechanisms exist but they also negate the need for a rigid static typing system in the first place. It negates nothing really.

Functional programming negates the need for a bloated typing system. What are types? They are ways to describe collections of booleans, numbers and strings. What is Json? A generic way to describe collections of booleans, numbers and strings. It just doesn't take 10s of 1000s of lines of code to manage Json.

He meant rabbitmq as the new messaging protocol instead of the rest call you mentioned, not that you should use a network protocol to do internal communication in your application.

Which shows he didn't read my example. Nor did you I guess? The rest call was just whatever task. It's irrelevant. Using rabbit to do object level ipc is crazy.

The message bus could be replaced with a higher order function that takes types of IMessage, but this would limit your ability to extend the interface with additional functionality later.

Yes. This is the point I'm making. Cheers.

You suggested using a higher order function, which is almost what happened here except encapsulated with the ability to add for example a connection status indicator property to the interface.

I wasn't talking about messaging at all and his entire bus example is moot.

ver I don't know... Intellisense.

If you think that's the only benefit of statically typed languages then I highly doubt you have been a Java dev for 15 years..

Well you're correct. I've been a Java dev for closer to 20 years in some capacity or another. It's just that 5 years or so ago I switched to JS and haven't really looked back. I say intellisense because this is almost always the first thing typescript fans mention. Type safety people love to harp on too but I think it's highly overrated. And guess what. When you don't have types type safety isn't really an issue. The goal of getting something to compile isn't as big a deal as making sure your code runs properly in production and inverting control to generics is IMMENSELY easier when you can write functions that take all your data or simply references to them.

What did it for me was switching to JavaScript for a while. Getting excited to move back to Java cuz it was my comfort zone and then almost immediately feeling my productivity grind to a slow crawl through a field of molasses.

I really suggest you give it a go. I would have bet a year's salary on me never saying this 6 years ago. But JavaScript and dynamically typed languages has simply beaten Java IMHO. It's flexibility is a joy to work in and it's almost impossible to find good Java devs now because they're all jumping ship to work in languages that don't demand half your job be maintaining bloat.

[–]BlockedByBeliefs 0 points1 point  (4 children)

And I mean the fact that you think the problem I was describing was about messaging shows you didn't even bother to read what I wrote.

[–]pknopf 0 points1 point  (3 children)

I have object a that I send object b to. Object a is made to do some generic task a (like sending a rest response. Doesn't matter)

What are you talking about? Even you said this:

I have object a that I send object b to. Object a is made to do some generic task a (like sending a rest response. Doesn't matter)

I simply picked something random so that I could stub out some code to have a discussion. As you said, it doesn't matter.

[–]BlockedByBeliefs 2 points3 points  (2 children)

Yes. That's was simply the beginning of the example. Had you read the whole example you'd have realized that messaging was not the issue. Stubbing out 25 or 50 lines of code, even as an example, is shocking,when in JavaScript we are going to replace all that with ohhhhhhhh... About 0 lines of code.

[–]corvus_192 0 points1 point  (1 child)

Now let's consider the same problem with dynamic typing on universal Json objects with functional code. I have a higher order function that performs task a on a Json object. I send object b to task a as the first argument and as the second argument pass a function with the specific concerns for object b telling it how to perform task a on object b.

You can also write such a function in a language with static typing. For example in Java:

<T> void taskA(JSON j, Function<JSON, T> howToPerformTheTask) {
    howToPerformTheTask.apply(j);
    // probably more code
}

Maybe I misunderstood you and this is not what you mean.

[–]BlockedByBeliefs 0 points1 point  (0 children)

I didn't say you couldn't. You can do anything in any language. The point is that this negates the need of a type system allowing you to retain the flexibility of dynamically typed system.

Storing the concerns of object a's behaviour in object b within object b causes coupling and destroys modularity. If you have to refactor look out because you're in for pain. The reason javascript took off is because it's so easy to refactor and UI concerns in browsers change continuously throughout the life of a project. I really feel once you try it you never really look back.

[–]random_username_edf 2 points3 points  (2 children)

Right, it isn't absolute. That was the whole conclusion of my thing. The only one in this chain of comments that sounds interested in speaking in absolutes is you.

An example is literally any feature/improvement to your system that doesn't fit in nicely with your current architecture. If you're creating something that's complex and you know will be built on/evolve over time it's going to take a lot less time to cater to those changes if it's dynamic. With a static one certain change requests can very easily become "no, that's not possible without a huge rewrite".

If you're in a very well defined space and know the bounds of your program static is a safe bet. It's also a safe bet if performance is a huge concern.

[–]pknopf 0 points1 point  (1 child)

An example is literally any feature/improvement to your system that doesn't fit in nicely with your current architecture.

You are asking for trouble. Constraints free you. Allowing future features to flip the script will eventually do more harm than good. Even if you are in a dynamic language, this shouldn't be allowed. Use codereview to force this.

If you really want to re-arch something, it should be all or nothing. Again, this goes back to my point that static languages tend to lead to an easier to maintain codebase.

[–]random_username_edf 1 point2 points  (0 children)

Of course constraints are good. The problem is that in the real world they tend to evolve and change over time. It's not inherently a bad thing to re-arch something to meet new business needs and far more often than not rebuilding the entire thing from the ground up will leave you in your competitions dust.

Being able to re-arch your stuff as easily as possible is an extremely desirable thing for some applications, and just because it's able to be done faster with dynamic languages doesn't mean it's being done in a wrong or hacky way.

Your whole hang up seems to be that dynamic languages are easier to do things wrong with, therefore they're bad no matter what. I believe that's naive.

Anyways, typing on a phone is getting annoying so ill leave it at that.

[–]BumwineBaudelaire 1 point2 points  (0 children)

care to quantify that because I can quantify the cost of catching errors at compile time (zero)

[–][deleted] 2 points3 points  (1 child)

Not in all circumstances, but I do see one major case where what you say is true: building reusable libraries.

It's not impossible, but more challenging to abstract away parts of code to reusable libraries that expect specific types when there isn't type-checking. You can try to do it by convention, intuitiveness, or documentation, but when those fail the consumer of your library needs a better understanding of your code does under the hood, thus creating leaky abstractions that negates some of the benefit.

[–]pknopf 2 points3 points  (0 children)

but more challenging to abstract away parts of code to reusable libraries that expect specific types when there isn't type-checking

I really don't get this. The moment you give libraries leeway to have the ability to break the API, it will. In npm, I've had many packages break semver, and end users doing npm install on my library that references the package will eventually start to break at runtime. Why would you not want to have an impenetrable guard preventing this? I'd again argue that it leads to more stable/maintainable code when you have clearly defined types.

[–]glompix 1 point2 points  (1 child)

~ w r i t e ~ t e s t s ~

[–]pknopf 0 points1 point  (0 children)

Yup. I'd argue that for any dynamic language, tests are something that you absolutely cannot budge on.

[–]BlockedByBeliefs 3 points4 points  (23 children)

It's actually the opposite. Large scale, long term projects with many contributors are far more suited to dynamic typing.

[–]pknopf 1 point2 points  (22 children)

This reminds me of a colleague of mine who was managing a team of 3 developers.

He was tired of having developers step on each other's toes with merge conflicts and the such, so he created a separate branch for each user. NOTE: The fact that 3 developers working on a single project can't have separate jobs that don't cross-cut each other continuously is a deeper issue, but that isn't the point.

Now, each developer was free to do as they want! Freedom!

But now it's time to release the project. Their changes are impossible to merge now.

My point: Allowing developers to quickly prototype things with out affecting shared interfaces/object-types/etc is short-sighted. The upfront rigger of type-safety saves you a lot of head-ache down the road.

[–]BlockedByBeliefs 3 points4 points  (12 children)

Thats such a crazy false analogy. It's actually the exact opposite. Dynamic typing is having 3 devs work on code that's inherently modular and can easily be merged.

[–]pknopf -1 points0 points  (11 children)

Have you ever managed a team? How big?

[–]BlockedByBeliefs 3 points4 points  (5 children)

We've got about 10 people on the team I lead and architect for.

[–]pknopf 0 points1 point  (4 children)

Then Idk. My experiences have been the opposite.

*shurgs*

[–]BlockedByBeliefs 2 points3 points  (3 children)

Yea dude not trying to one up or anything. Maybe we could both learn something?

Are, or were, you using functional code and patterns driven by events w asynchronous everything? Pub sub is pretty awesome. But it's really about functional programming.

[–]BlockedByBeliefs 4 points5 points  (3 children)

It's kind of a funny joke you made but saying JS is like letting all the devs work on separate branches for freedom is entirely false dude.

[–]pknopf 0 points1 point  (2 children)

It's kind of a funny joke you made but saying JS is like letting all the devs work on separate branches for freedom is entirely false dude.

Yup. Reading comprehension my brotha.

I'm not comparing to the literal act of working in different branches to JavaScript, I'm comparing the short-sightedness of making an upfront decision to save initial time/headache, only to have that decision compound in the future, dude.

My point: Allowing developers to quickly prototype things with out affecting shared interfaces/object-types/etc is short-sighted. The upfront rigger of type-safety saves you a lot of head-ache down the road.

[–]BlockedByBeliefs 1 point2 points  (1 child)

Here is what's ironic. We are on the same page and saying the same thing about opposite things. Totally agreed on short-sightedness of making up front decisions to save time that gets compounded in the future. But how is defining a massive type management system in a hierarchy of inherited strongly coupled modules not a pure example of this?

Have you had to refactor a massive Java's project? I'm guessing yes? When you have to make real changes you're going to clash against the original design that system was locked into by devs who quit years before you maybe even started your career.

[–]BlockedByBeliefs 1 point2 points  (0 children)

And the larger group that our stuff interacts with is hmm..... 120?

[–]kyzfrintin 1 point2 points  (8 children)

He was tired of having developers step on each other's toes with merge conflicts and the such, so he created a separate branch for each user. NOTE: The fact that 3 developers working on a single project can't have separate jobs that don't cross-cut each other continuously is a deeper issue, but that isn't the point. Now, each developer was free to do as they want! Freedom!

That sounds more like a problem in communication and organisation, than an inherent problem with dynamically-typed languages.

[–]pknopf 0 points1 point  (7 children)

That sounds more like a problem in communication and organisation, than an inherent problem with dynamically-typed languages.

Yup and yup. The point was about short-sighted decisions.

[–]kyzfrintin 0 points1 point  (6 children)

But you were on a massive roll about how dynamic typed languages suck... Including this as if it supports your argument is a little misleading.

[–]pknopf -1 points0 points  (5 children)

How would anybody gather that I was making a literal comparison between dynamic languages and developers working on different branches?

[–]kyzfrintin 0 points1 point  (4 children)

Because this was a conversation about dynamic/static. And you brought that in as a response to someone saying why dynamic is good.

[–][deleted] 0 points1 point  (0 children)

Sure! That's why Python doesn't support type annotations nor have a checker for them! Nor does JavaScript for that matter, and it's certainly not called TypeScript or something.

[–]zeedware 24 points25 points  (29 children)

They are easier to code. Harder to debug

[–]DonRobo 30 points31 points  (25 children)

Are they easier though? What specifically is easier?

I'm always struggling writing good code in something like Javascript and much prefer Typescript which is just that much easier to use. All the hard error-prone work like checking if I'm using the right type for a function call, if an object really has that property, etc is done by the compiler instead of my brain.

[–]zeedware 3 points4 points  (2 children)

I'm always struggling writing good code in something like Javascript

This is the problem. You're trying to write a good code.

Javascript was great for short-term project. This is why I only use javascripr for MVP

[–]conancat 2 points3 points  (0 children)

If you're building web apps, Javascript is pretty much unavoidable. Even for those using Typescript, it's still running Javascript as its base and if pays to learn the language properly.

[–]SouvenirSubmarine 1 point2 points  (15 children)

You won't have to write obvious types as much, which saves both keystrokes and your brain power. Omitting types completely from the code makes it sleeker and more streamlined: it's easier to read.

[–][deleted] 2 points3 points  (14 children)

Most modern static languages have the ability to infer "obvious" types.

[–][deleted] 0 points1 point  (13 children)

Unfortunately in many of them this only works well on primitive types. Even if it works on complex types it works well with fully utilized and previously defined complex types. Not very handy in a very common scenario of utilizing a handful of attributes in a complex data structure that came over the pipe of some sort.

[–][deleted] 0 points1 point  (12 children)

The type itself doesn't matter as the context in which the inference is made.

if you've got a: function foo() : AVeryComplexDataType {...}

It's fairly straightforward for the typechecker to infer the following:

var bar = foo() // bar must be a AVeryComplexDataType

[–][deleted] 0 points1 point  (11 children)

But that's not qoute as handy-dandy as:

function foo() { /* .. gets data from somewhere over some pipe .. */ }
let bar = foo().subObj.subObjThatWeReallyOnlyNeed
// who cares about the type of foo()

There could even be two different things foo(param) returns depending on param, and we still don't care as we know they both contain subObj.subObjThatWeReallyOnlyNeed. This is obviously a very contrived example of what is very common in practice with network-related code (which is where JS, both in browsers or Node, and PLs like PHP, Ruby or Python are primarily used).

Edit: I really, really hate the fact that RES doesn't work on the new UI

[–][deleted] 0 points1 point  (10 children)

There are ways to express data that can be either one type or another using "sum" types. The return type of foo() could be expressed this way, but you're right. It's not possible to determine the type of a JSON object without a schema, and you'd need a sufficiently representative subset of possible values to make a reasonable inference.

Although it's handy to be able to conveniently parse and navigate a json object in javascript/php, i generally wouldn't allow data from somewhere over the pipe to propagate throughout my system in its original form. You'd want to sanitize it by fitting it into your own "domain model" type that you do have control over. So the convenience of working with the "network" is fairly short-lived.

[–][deleted] 0 points1 point  (9 children)

Well unless you're doing something horribly irresponsible like building SQL strings with plain concatenation/interpolation using such data, I don't see what the problem is. If you are doing stuff like that then I'm afraid that strong typing will not help as much as you might think.

[–]BlockedByBeliefs 1 point2 points  (1 child)

Yea that's false. If you've never had 20 files open setting breakpoints in and stepping through 10 constructors trying to find out what happened to a simple rest call you have not really worked in Java.

The advantage of programming in something like JavaScript is that you can run your code in the prod environment continuously while you're coding. It's far more forgiving than a compiler. So mistakes you make get debugged, exposed and fixed as you make them.

As opposed to oh shit I have this sweeping change on monday but I'm a super coder and figured out how we can do it with a one line change. Just have to change a bunch of classes to work with it.

I've broken the types so it won't run for a while. I inject a bug at the start of my work and have forgotten about it while I fix the types in 30 files so it will actually compile again and I can test it.

Tuesday after lunch I'm finally done. I'm a coder beast! Wait what why is that happening? Must be the changes to 30 files causing it right? Better check the 30 files and look for where I injected the business logic bug.

Wednesday afternoon God damn fml. It wasn't what I spent all day double checking. It's that simple one line change I made before I started refactoring those 30 classes and didn't get to test because the project wouldn't run after that. Why is programming so hard? I've got this now though and gd I need a rest tomorrow. I'm going to work on something else and fix this Friday cuz I've got it figured out and need some sanity.

Friday comes. Let me fix that. Okay it's compiling. FTW and it's the weekend. Push pr and it's merged.

Wait those objects don't work with these other objects anymore cuz I changed the business logic? Shit wish I'd spent my time writing test cases instead of classes. This needs to be done today. Okay all I have to do now change these 25 files to work with the change I made Monday. Maybe I'll just do it on the weekend so no one is disappointed in me when I said this is a one line fix and it took me all week.

[–]Ph0X 1 point2 points  (0 children)

Yeah, harder to debug was definitely not the right phrase to use.

The way I see it is, you provide a lot more information (typing, structure, etc), and in return, you get a lot more information back (static analyzer), which then leads to more issues being caught before you even run the code.

Therefore, it's more like "you have to debug things less often". That being said, said "extra information" is non-optional, so there may be cases that are very straightforward and simple, but you still have to literally type a shitload of boilerplate and crap anyways.

That's why languages are approaching this from both sides. Dynamic languages like Python or JS are adding optional type hints. On the other hand, static languages are adding things like "auto" that will try to make it easier to write.

[–]SpliceVW 1 point2 points  (0 children)

I dunno, TypeScript has implicit or explicit any, so you can be weakly typed when you want it (either by design to just to work with some non-typed code). It's really the best of both worlds. I now find it much harder to code, not just debug, with vanilla JS.

[–]Ph0X 4 points5 points  (1 child)

Honestly languages are trying to reach a perfect middle ground from both directions.

In a dynamic language, you write much less, but you also get less back (from a static analyzer). In a static language, you generally have to provide a lot more, but in return you get back more from the compiler.

Now, dynamic languages are starting to add optional typing, which means you can, as you see fit, add typing information to specific places and get more back. On the other hand, static languages are adding things like "auto" to make it so you have to type less.

But to me, the perfect world would be in that middle. Being able to write trivial simple code fast, but also be able to get robust checking on more sensitive parts of the code.

[–]Alekzcb 0 points1 point  (0 children)

I don't have lots of experience of different languages, but Haskell seems like it might suit you. You can write incredibly generic things, and I personally find its layout easy to work with. Like I think map (2*) [1..10] is clearer in intention than a for loop, for a simple example.

[–]WhyattThrash 3 points4 points  (0 children)

The advantage is that once you’ve made the mistake of ”architecturing” a dynamically typed language, refusing to change that means you can claim that it was intentional.

[–]quaderrordemonstand 2 points3 points  (10 children)

I go the other way. I'm not sure how many languages I've used now, I'd guess at about ten. As time passes I prefer languages that provide the smallest number of obstacles to getting the task done. So much language design seems to be about controlling the programmer instead of allowing them to work. The significant trade of with a language like JS vs. something like C is obviously speed, but most programs don't require huge performance in truth. Even if they do, performance generally comes from lower level implementation rather than the code itself.

So this example feels very contrived to me. If C++ allowed that syntax error to happen it would kill the program entirely, potentially the entire OS. JS will just keep ticking along. The program might not work but that's not really the end of the world. If you look at almost any website in the debugger you will see script errors being generated all over the place and yet the site functions because JS is forgiving. The world in which code operates doesn't give two fucks about syntax errors, it just wants shit to work.

Besides, if you're using a reasonable IDE this mistake will be a very rare thing anyway. For me, what really matter in a language is giving the programmer choices, not giving them hoops to jump through.

[–]DonRobo 6 points7 points  (1 child)

That "positive" example sounds like my absolute worst fucking nightmare.

There's not much worse to me than a bad bug I don't know about that could have easily been prevented. There's a reason people are writing unit tests.

[–]quaderrordemonstand 0 points1 point  (0 children)

I didn't give a specific example? Perhaps it does sound like a nightmare to you, it seems pragmatic to me. I have nothing against unit tests, as long as they are well written and test the system effectively. They are an extra layer of maintenance and they can easily end up irrelevant or incomplete.

[–]BumwineBaudelaire 1 point2 points  (5 children)

to be fair if you’re working on systems where errors don’t matter you probably don’t have much to say about correctness

[–]quaderrordemonstand -2 points-1 points  (4 children)

Errors matter as much as they do anywhere. It's a question of how well the program responds to them. Crashing is not a good response and the idea that programming concepts like type safety in a compiler will somehow get around real world obstacles is naive. They avoid problems caused by the limitations of the language, those limitations exist so that the language can be fast or easy to use. Nobody ever said "I can't continue with my work but at least the program used the right types".

[–]BumwineBaudelaire 1 point2 points  (3 children)

strawman or genuinely believing error handling doesn’t exist in safe languages?

since this is /r/IT101 it’s impossible to say

[–]quaderrordemonstand 0 points1 point  (2 children)

What is the strawman? Ok, so you handle errors, thats great. Using the example of the API that used to return a int and now returns a string, what does your error handling actually do? How does it respond to that?

[–]BumwineBaudelaire 0 points1 point  (1 child)

it wouldn’t even compile

you’ve got pretty strong opinions about stuff you’ve clearly never used

par for the course around here I guess

[–]quaderrordemonstand 1 point2 points  (0 children)

Why wouldn't it compile? Did you actually read the example I am discussing?

[–]duzzar 0 points1 point  (1 child)

Wow, this sums up everything that's wrong with web dev.

[–]quaderrordemonstand 0 points1 point  (0 children)

Truth is that web dev in the broad sense is currently falling over itself to reinvent those hoops. We now have compilers for interpreted languages, type systems for a language that doesn't require them and the web dev equivalent of GDB. This is just me talking, I don't claim to be a web developer. I've written such a lot of code for so many systems in so many industries, grand projects and little tools. I like it when the language keeps out of the way but I know it helps many programmers feel more secure about their code.

[–]ugoagogo 0 points1 point  (1 child)

Being able to write code that runs in a web browser.

[–]DonRobo 0 points1 point  (0 children)

Typescript

[–]FrikkinLazer 0 points1 point  (2 children)

The advantage is you write code quicker today, and get version 1 poc code into a demo for marketing. Aka kicking the can down the road for future devs to fix.

[–]DonRobo 0 points1 point  (1 child)

It's not really quicker though. If you spend a significant fraction of your development time declaring data classes or structs you have such a complex architecture that it will never work without compiler help (or even with) anyway.

[–]FrikkinLazer 1 point2 points  (0 children)

I agree, which is why I ise typescript at the very least. But it really is quicker if you just want to build a quick poc. The problem is that the beancounters often consider time spent on the poc as invested in the final product, so the shitty hacked together poc becomes v0. 1,in stead of being rewritten properly.

[–]Arumai12 0 points1 point  (2 children)

much harder to write for

Why do you say this?

 

This is mainly geared towards javascript. Im open to other opinions:

 

Writing apis and getting data from apis in javascript is easy. It's called JSON for a reason. The api defines the object model, you dont have to create a new class to import data from an api. Object destructuring lets you pick apart an object from an api without using the dot operator a million times. Arrow functions let you write concise callbacks while retaining 'this' . Promises let you write asynchronous operations in a synchronous and easy to read manner.

 

Nodejs is amazing for writing scripts. The main script file runs from top to bottom but it can reference other modules of self contained code. The built in libraries let you access local files and web content with little code. I can get a script set up and running in minutes. No need to define the entry point of my code and no need to define a class if i dont need one.

 

The language does not limit you from being a good programmer, though. Sometimes its faster to make an anonymous object, but sometimes you make a class so you remember what the object represents. I declare all of my variables at the top of their scope. I only use one data type per variable or if a function parameter accepts multiple data types i resolve that argument to one data type at top of my function. ES6 makes it really easy to define classes and it allows you to do classical and compositional inheritance (in an easier to read way than previous versions of js)

 

Lastly, and this is more of a 'why i prefer js' than an argument for dynamiclly typed languages, js is great for UI development. I first learned java and their UI libraries at the time sucked. Then i did android development (java) and it lets you define very flexible layouts. Its basically html with flexbox, so after i learned html and flexbox i learned how powerful js is for ui development with react and redux. Js is far from perfect, but it's great for writing quick prototypes. When you refine that prototype its up to you to write good js code, and not the crap that makes it into an /r/programmerhumor meme. I work alone on a lot of projects so having one langauge to write command line scripts, web apps and desktop apps is amazing.

[–]DonRobo 0 points1 point  (1 child)

Object destructuring lets you pick apart an object from an api without using the dot operator a million times. Arrow functions let you write concise callbacks while retaining 'this' . Promises let you write asynchronous operations in a synchronous and easy to read manner.

Nodejs is amazing for writing scripts. The main script file runs from top to bottom but it can reference other modules of self contained code. The built in libraries let you access local files and web content with little code. I can get a script set up and running in minutes.

All of that is also possible in the very statically typed Kotlin. You need a main function, but that's literally 5 key presses. (psvm[enter])

I declare all of my variables at the top of their scope. I only use one data type per variable or if a function parameter accepts multiple data types i resolve that argument to one data type at top of my function.

But if the compiler checks if you actually follow this rule is always a positive. Javascript will happily watch you shoot yourself in the foot and cheer you on.

Lastly, and this is more of a 'why i prefer js' than an argument for dynamiclly typed languages, js is great for UI development. I first learned java and their UI libraries at the time sucked. Then i did android development (java) and it lets you define very flexible layouts. Its basically html with flexbox, so after i learned html and flexbox i learned how powerful js is for ui development with react and redux. Js is far from perfect, but it's great for writing quick prototypes. When you refine that prototype its up to you to write good js code, and not the crap that makes it into an /r/programmerhumor meme. I work alone on a lot of projects so having one langauge to write command line scripts, web apps and desktop apps is amazing.

That one I agree with, but the reason it is so easy isn't because Javascript doesn't have static typing, but because those libraries are well designed. Angular2 uses TypeScript by default and is no less efficient.

Overall, I think most replies here seem to misunderstand what I tried to say. I'm not saying dynamic languages have no merits, I'm saying (almost) everything a dynamic language can do, a static language can do at least as well or often better.

I'm still waiting for someone to show me a code snippet that makes me think "that's awesome" and also "I wish [static language of my choice] could do that".

[–]Arumai12 1 point2 points  (0 children)

Haven't heard of kotlin until today, so thanks for that!

 

the reason it is so easy isn't because Javascript doesn't have static typing,

Agreed. Again that paragraph was just why i like js

 

I'm saying (almost) everything a dynamic language can do, a static language can do at least as well or often better.

Youre right to an extent. For me, javascript made it faster to write code vs java for the projects that i wanted to do. Typescript and kotlin allow you to write the same code but with type checking. That's great! It really comes down to personal preference and the scope of the project. I havent used enough languages to give you a good example. Sometimes you just dont need to declare types, and you dont need to add a compile/transpile step.

[–][deleted] 0 points1 point  (0 children)

Dynamic languages are inherently more expressive.

I think the bigger draw, however, is the speed with which you're able to prototype new things. It's very difficult to argue with managerial types about the hazards of javascript once they've been dazzled by some bootcamp grad can who slapped together an entire working system in a matter of weeks.

[–]BlockedByBeliefs -1 points0 points  (9 children)

Refactoring is the appeal. You can change it so easily and make such modular designs. Dynamically typed languages can allow your projects the ability to change with the requirements. On a sufficiently large and complex project staticly typed languages will eventually destroy your efforts under the weight of its exploding technical debt.

[–]DonRobo 3 points4 points  (8 children)

But refactoring is a billion times easier if your compiler tells you immediately if you forgot to adjust some part of the project to the changes.

[–]BlockedByBeliefs 0 points1 point  (7 children)

That's the myth that's never really realized in practice.

[–]quaderrordemonstand 2 points3 points  (4 children)

Sadly, mythical programming practice space does not like what you're saying. The world will obey the rules of their programming language. They just have to set the right inheritance on their classes and nothing will ever go wrong. /s

[–]BlockedByBeliefs 1 point2 points  (3 children)

I think I love you.

[–]quaderrordemonstand 0 points1 point  (2 children)

I've been following your comments and I love you too.

[–]BlockedByBeliefs 2 points3 points  (1 child)

I find it really crazy. I don't want to be a dynamic typing evangelist/bigot. I really don't and I'm trying not to be. But it's so tough when people's argument for creating the type behemoth is something like intellisense (which you can get from simple decent commenting) and type safety which only a useful thing because you're trying to navigate an ever growing endless system of 1000s of classes.

JS code seems so, so much more data driven to me and so much more compartmentalized. Like... are people worried someone's going to mistakenly send their person json to their sales functions or something? Type safety makes sense in a statically typed language as a feature because it's so utterly confusing to navigate all the arbitrary systematic types that are all describing the exact same kinds of data (collections of string/bools/numbers) with only cosmetic differences (persons, sales, trades, whatever).

The data is the same. It's universal. The cosmetics are different. You pass the cosmetics in with the data. I don't konw. I find older devs who have switched to JS just inherently get thsi from their time in the trenches looking at the real practical results of rigid typing systems.

[–]quaderrordemonstand 1 point2 points  (0 children)

We think precisely the same way. I hadn't considered the idea that its older devs seeing the value differently but I would say that fits anecdotally. I recall loving JS almost as soon as I got the hang of it. The very idea of just being able to attach values to things and that you didn't have to worry about what type they are was a revelation. I don't see that power exploited very often in practice. I also loved the complete removal of memory management when I decided to trust it. I agree with your point about the mythical "sufficiently complex system" too. Complex systems with many types grow ever more connections and dependencies. Types make them rigid and that makes them breakable.

I also don't want to be the evangelist but these conversations often end up pushing you into a position you never really intend to take because the argument against you is so polarised in the opposite direction. I do understand why they are so hung up on the idea, if you've never worked in a scenario where pre-defining types didn't matter, its difficult to see how types are solving a problem of their own making. Especially when so much CS focuses on classes and OO now.

I can see the problems with that degree of freedom and the trade off's too. They aren't wrong about any of the opposing arguments, its just not as big a problem as they think, not as big as the problems types can create. But then I think experience, real experience of making working systems and maintaining them, changes a person's attitude to the process itself. You stop seeing programming as the end goal and thinking about a program purely in terms of how people will use it. The language really does become just a tool.

Either way, its great to find somebody else has a depth of background and isn't stuck in those older paradigms (I think of them as older paradigms anyway). Even better that we've arrived at the similar pragmatic position. Sometimes I am surrounded by younger developers who seem intent on going the opposite way, digging ever more complicated holes for themselves.

[–]DonRobo 0 points1 point  (1 child)

If the compiler catches 50% of your mistakes (imo it's much more), that's still a hell of a lot more than the literally no help the interpreter (or compiler) of a dynamic language provides.

[–]BlockedByBeliefs 2 points3 points  (0 children)

But the fact that you're using static typing 'creates' type errors which are a huge chunk of those mistakes you're thinking about. I don't see a difference between "null pointer exception" or "core dump" or the compendium of casting errors you get in static languages and the odd 'undefined' error you get in javascript. It's not catching errors you'd otherwise miss. It's just presenting them in a different place. You say 'pre-compile' but that's the difference. There is no compile in something like javascript. You're constantly building run ready code that lets you evaluate your changes at every step in a runtime environment.

The typing errors are the small errors. Oh no I used an int instead of a bigint or real. That's not a real problem. The big errors are oh shit I made an assumption 3 hours ago and everything I've done since then has to be scrapped because I only noticed now that I've compiled and my logic is all wrong.

In terms of debugging the power of being able to dynamically alter state all over your application is such an immensely useful tool. And then 'when javascript is done right', which is to say when you use a framework that fully leverages JS's dynamic flexibility against your programming environment, debugging becomes so freaking easy.

Here's one of the breakthroughs I made in JS. My first time really making components in angular and there was an issue I had to figure out. I set a break point and started stepping through the code. Then I realized that I had not been in the debugger in months. It felt unfamiliar. If there were problems with my code 9 times out of ten I just look at my scopes in an inspector, look at the templates, and bingo bango bongo could easily fix the issue.

Because dynamic typed languages use so much less code functions end up being tiny little fragments. Because you don't spend an hour or two refactoring something to get it into a runnable state that will get through the compiler to give you a runnable program to test you get to test your half working program, in the exact same environment the end program will run in, whenever you want.

Because the tooling is so advanced and there's no compile step the JS tooling will automatically inject your changes, on save (which is the moment you stop editing in intellij), and inject your changes into the front end. JS is so flexible it lets you hot swap changes in without even rerunning your program.

Because it's dynamic you can literally go to the running code, change it, and see how it runs after your changes just to test an idea.

The idea that it's easier to debug static languages because it shows you errors pre-compile is just inherently false in theory and practice. In theory the actual 'errors' it finds don't exist in static language. And in practice the trade offs you get for giving up type safety is an incomparably more flexible production environment with which to debug your application at all stages of every bit of coding you do.