Live data from Hacker News

Fear, trust and JavaScript: When types and functional programming fail

reaktor.com

161–170 of 210 posts

Re: Fear, trust and JavaScript: When types and functional programming fail

#161

Earlier quoted context omitted.

> Being dynamic doesn't preclude variables from being type checked by the runtime. It kinda does, because in a dynamically typed (as colloquially defined - if you want to debate that definition, that's another discussion) language, variables don't have types - values do.

Ok, if you want to be pedantic about it, fine. Nothing precludes values from being type checked.

Type checked against what, if a variable doesn't have a type?

There are contexts in which two values are involves, where we can at least check that the types are matching (or reasonably compatible), like (a + b). JS is a massive failure in that regard, too, and there are dynamic languages that do it far better - e.g. in Python, ("1" + 2) is a runtime type error, not 3.

But in the context of this thread, I feel that's not what we're talking about. We're really talking about contracts - and contracts require typed bindings (variables, function arguments etc), not just typed values. Which means that they do require static type annotations. As we've discussed in another subthread, those annotations might be checked dynamically - but they still have to be declared statically by the coder, which makes the type system effectively static from their perspective.

To put it differently: if you require types to be declared explicitly, there's no reason to not check them statically. Dynamic checking of static types really only makes sense for gradual typing systems, where code with static type annotations might be called from some non-annotated code, and you want it to be possible without forcing static typing on the caller. At that point, yes, you can have a dynamic type check in the callee, which ensures that if code without type annotations doesn't actually get the types right, things fail fast at the static/dynamic typing boundary, instead of allowing it to propagate into the statically typed code (as is the case in e.g. TS today).

Re: Fear, trust and JavaScript: When types and functional programming fail

#162

Earlier quoted context omitted.

Ok, if you want to be pedantic about it, fine. Nothing precludes values from being type checked.

Type checked against what, if a variable doesn't have a type? There are contexts in which two values are involves, where we can at least check that the types are matching (or reasonably compatible), like (a + b). JS is a massive failure in that regard, too, and there are dynamic languages that do it far better - e.g. in Python, ("1" + 2) is a runtime type error, not 3. But in the context of this thread, I feel that's…

> if you require types to be declared explicitly, there's no reason to not check them statically.

I think some of this thread is suffering from confusing terms so, my entire point is this:

There is no native way in javascript to say that the first argument of function foo must be an instance of class Bar (which in JS could be a string or an array or some custom object or even a DOM element - everything is an object and thus has a 'class').

The common response is "use typescript" which means you write the code with argument type declarations, and then compile to javascript. This (in theory) means any code you've written in the project in TS which calls our foo() function, will warn/error if the first argument isn't an instance of class Bar.

But, and this is the problem: it's not enforced by javascript, it's "enforced" (for whatever definition of enforced typescript uses) by the TS compiler.

So if I then use the compiled JS of function foo() and call it from native JS (i.e. not compiled by TS) - it won't tell me I have the wrong type.

THAT is my issue.

Re: Fear, trust and JavaScript: When types and functional programming fail

#163

Earlier quoted context omitted.

I really like the type system in Powershell and wish JavaScript had something similar. Typescript is a mess by comparison. [string]$String = "Dog"; $String = 5; Cannot convert value 5 to type "System.Objects.String"

This produces a similar error ("Type 5 is not assignable to type 'string'") when compiled with TS: var s: string = "Dog"; s = 5; The difference is that it's a compile-time error, while in PowerShell it's a run-time check. But what's the difference in this case? Either way, it tells you.

The biggest difference - not needing to compile - is offset by the slowness of Powershell. If only one language was best across all metrics.

Re: Fear, trust and JavaScript: When types and functional programming fail

#164
post #136
post #58

Earlier quoted context omitted.

I’m still amazed by how much faster transpiling from Reason is compared to TypeScript or JavaScript is via Babel.

OCaml as a language is so close to a sweet spot between performance and ergonomics in my experience. I'm not sure if the Bucklescript compiler is generally running on Node or natively, but that could also be a big variable at play here.

Afaik it's native. The `bs-platform` node package contains native binaries.

Re: Fear, trust and JavaScript: When types and functional programming fail

#165

> in various cases the types are wrong and the compiler doesn’t care It's disturbing how often I encounter this in TypeScript. Or its inverse: the types are correct and the compiler is wrong. Or a third common problem: the types for a library are incorrect. The unsoundness of TypeScript is not merely theoretical. The compiler is frequently just wrong. For that reason, I am mystified by the amount of enthusiasm for Ty…

100% agree with this. If you're using redux the boilerplate of Typescript is huge. To do that all that work and still have the compiler miss problems at the state level deemed Typescript pointless to me.

Not sure which specific issues you encountered, but I had issues with defining actions and using their types in a union to the reducer.

There is a nice little library [1] that fixes this issue.

So a general redux setup looks as follows:

    const FETCH_USERS_BEGIN = "@@FOO/FETCH_USERS_BEGIN"
    const FETCH_USERS_SUCCESS = "@@FOO/FETCH_USERS_SUCCESS"
    const FETCH_USERS_ERROR = "@@FOO/FETCH_USERS_ERROR"

    const fetchUsersBegin = () => action(FETCH_USERS_BEGIN)
    const fetchUsersSuccess = (users: IUser[]) => action(FETCH_USERS_SUCCESS, users)
    const fetchUsersError = () => action(FETCH_USERS_ERROR)

    type IActions =
      | ReturnType
      | ReturnType
      | ReturnType


    interface IUser {
      id: number
      name: string
    }

    interface IState {
      readonly isLoading: boolean
      readonly isErrorLoading: boolean
      readonly allIds: number[]
      readonly byId: {
        readonly [key: number]: IUser
      }
    }

    const defaultState = {
      isLoading: false,
      isErrorLoading: false,
      allIds: [],
      byId: {}
    }

    const reducer = (state: IState = defaultState, action: IActions) => {
      // narrowing on types
      switch (action.type) {
        case FETCH_USERS_BEGIN:
          return { ...state, isLoading: true, isErrorLoading: false }
        case FETCH_USERS_SUCCESS:
          return {
            ...state,
            byId: action.payload.reduce(
              (acc, u) => ({ ...acc, [u.id]: u }),
              {}
            ),
            allIds: action.payload.map(u => u.id),
            isLoading: false,
            isErrorLoading: false
          }
        case FETCH_USERS_ERROR:
          return {
            ...state,
            isLoading: false,
            isErrorLoading: true
          }
        default:
          return state
      }
    }



[1]: https://github.com/piotrwitek/typesafe-actions#1-classic-js-...

Re: Fear, trust and JavaScript: When types and functional programming fail

#166

Earlier quoted context omitted.

I instead proclaim that it brings you the best of both worlds. Finding the right mix of static/dymamic is a balance act but if you do so you get the benefits of static types (safety, documentation, tooling) and dynamic types (fast prototyping, not having to write convuluted code to please the compiler). What are the killer features that gradual types lose out on?

As the old saying goes, "there's nothing more permanent than a temporary solution". In the context of software development, it means that "prototypes" get shipped as production code all the time.

Sure,and lots of codebases are completely untyped. I find it great that you can opt out of the theorem proving that type checking is when crunch time comes. As such it functions as a loan and your organization should strive to pay back the debt when it can. Nothing can save you if you never get a calmer period.

Re: Fear, trust and JavaScript: When types and functional programming fail

#167

Earlier quoted context omitted.

Could you elaborate on this a bit; do you have any interesting real life examples of this mentality?

Sure. I worked on the system which is now the customer admin for Square’s ecommerce platform they bought in Weebly. We were all learning Vuex, while also trying to ship code. Across a half dozen pages we had a half dozen slightly different ways of addressing Vuex data. It wasn’t so much complexity that a professional coder couldn’t keep it straight in their head. But it was a trivial amount of complexity to fix. Two…

That sounds like no one actually designed or architect-ed the system, and everyone just went off and built things without an overarching plan. This is sadly somewhat common in software projects. This could be due to a variety of factors but to chalk every software project up to "resume padding" seems like a simplistic take.

Using your example but applied to other companies, I've seen the below, or some combination of all:

* Unskilled devs that have never used any of the new technologies and spent little time prepping beforehand.

* Management who demanded unrealistic deadlines or demanded devs skip design phase in favor of shipping faster.

* Lack of technical leadership, senior engineers are hard to come by at many large orgs and are often overworked or too busy to be everywhere at once.

* Cut throat career minded individuals that always jump ship to the next new thing.

In your case, it seems insane that you would be writing software with multiple teams or even multiple developers without some overarching plan. It shows a clear lack of technical leadership on the part of management and senior engineers.

Re: Fear, trust and JavaScript: When types and functional programming fail

#168
post #12

I love TypeScript and use it in any new project I create. The author is right though, you need to have team discipline to avoid using the `any` type when it can be avoided, and immutability is not in scope. TypeScript is probably the closest we'll get to my personal ideal of static typing in JS, while understanding that you sometimes need an escape hatch to deal with dynamic typing as JS is a dynamic language. I thin…

But isn't that true for every software project? You need discipline to avoid most of the garbage that can be created by using any language or framework.

I've seen some of the worst java apps before, but no one says "never use java". It's generally accepted that skilled engineers can make clean, easily maintainable apps, and unskilled engineers make garbage apps.

This just sounds like sloppy engineering and a total lack of professional rigor.

Re: Fear, trust and JavaScript: When types and functional programming fail

#169
I'm not really sure what the author is getting at. You need discipline to avoid most of the garbage that can be created by using any language or framework.

I've seen some of the worst java apps before, but no one says "never use java, it's bad".

It's generally accepted that skilled engineers can make clean, easily maintainable apps, and unskilled engineers make garbage apps.

This just sounds like sloppy engineering and a total lack of professional rigor and in that case, why is javascript to blame?

Re: Fear, trust and JavaScript: When types and functional programming fail

#170

> In a dynamic language like JavaScript, it can be hard to know what the shape of your data is. You don't need static typing to program defensively. Static typing instead ensures a certain defensive position, but as a developer you can choose to program in such a way even in a dynamic language. That being said it is foolish to make a blanket assumption that data is doomed to confusion. The state and shape of data is…

If you think common sense can ensure safety then you are super human. I have a 10 million line program that outputs an extremely complicated dataset with hundreds of parameters. Occasionally one parameter disappears... at a rate of 1/1000 runs. This is a bug, but the bug bypassed everything. The system has 100 e2e tests of "defense" but because the bug happens 1 out of 1000 times, 100 integration tests did not have enough coverage to find the error... so the program made it to production...

Now with static type checking. That program wouldn't even compile. The compiler can prove that the program is wrong rather than you going through hundreds of unit tests to try to catch an error while proving nothing. Proving a program is wrong is better than writing billions of unit tests that cover the entire domain of a function.

Your strategy of using common sense to go through 10 million (exaggeration of course) lines of code is an effective strategy, but not an intelligent one.

Post reply on HN