6 ms·
> What thing that violates a type check would be "perfectly fine to do"? One good example is where you might treat records or "product types" as maps Let's sa
by dack 6y ago
> What thing that violates a type check would be "perfectly fine to do"?
One good example is where you might treat records or "product types" as maps
Let's say you want to write a function that can capitalize all the string fields in the object passed in. In a dynamic language, you could map over the values and apply capitalization trivially. It would be a one-liner.
In a static language, you'd have a few options, but none are great:
1. You could use "reflection" or some dynamic feature to do this, but lose type-safety
2. You could make the function take in the union of all possible data types in your system, and then write a mapping function for each one. Then you're duplicating the logic N times, or at the least writing a lot of conversion boilerplate.
3. You could write two functions for each data type in your system to convert to a Map<String, Object> or some such and back, which lets you operate on the maps. Again, lots of boilerplate. Maybe you use code-generation for this? That would add complexity.
In reality, you probably wouldn't even try to write such a function in a typed language because of how awkward it is. Maybe you'd just write specific translation functions for the records you know you happen to need. But I think that's what people mean when they say you're restricted by the type-system - because it can't verify those types of operations, you find workarounds when maybe that would have been the easiest way to implement something.
- adwn 6y agoAs a proponent of static typing (at least for larger programs): thank you, that was a very enlightening example for when dynamic typing can be superior to static typing.
- mssundaram 6y agoIt's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything) type T = { [k: string]: number }; const t: T = { one: 1, two: 2, three: 3, }; const makeUpperCaseKeys = (v: T): T => { const keys = Object.keys(v); return keys.reduce((p, c) => { const key = c.charAt(0).toUpperCase() + c.slice(1); return { ...p, [key]: v[c] }; }, {}); }; console.log(makeUpperCaseKeys(t)); // { // One: 1, // Two: 2, // Three: 3 // }
- dack 6y agoThat's great! Are you making the argument that I won't be able to find an example where doing some transform in a type-safe way is awkward in TypeScript, or just that this one example can be done in TypeScript? By the way, my example was meant to be more like User -> User where there are some string values and some other types of value. You want to do the transformation in a generic way, but still have the type-safe object come out the other end with all the expected keys.
- deleted 6y ago[deleted]
- sbergot 6y agoYou can try this with typescript 4.1 : interface User { name: string; age: number; } type CapitalizeProperties<T> = { [Property in keyof T as Capitalize<string & Property>]: T[Property]; }; type CUser = CapitalizeProperties<User>; var c : CUser = { Age: 17, Name: "john" } You can check that the autocompletion works on the c variable. https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=15&pc=2#code/JYOwLgpgTgZghgYwgAgKoGdrIN4ChkHIhwC2EAXMumFKAOYDc+hcdFRAriQEbRMC+uXGACeABxQBhOGOBg4AG2AAvCAAUoAewlQwwCOgA8AFQB8yALw5mAbQ3boo5KGQBrCCM0xkx5HHTI0rLySqqG1LQgdMgAZMj2OqKmALqUxnZaiSLJAkzC4lIYWFZBcooq6pmO+kZFUKZ5AG5wUMgIyJSSdZbWyACCbJQAjADsADT4AHKk7ABEAFaaABYgs7j8QA https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=15&pc=2#...
- deleted 6y ago[deleted]
- madmax96 6y agoThere is no limit on the number of problems easier to solve using dynamically typed languages. For an individual hacker, dynamically typed languages make a lot of sense. I don't forget what types my functions accept as I am writing a program. All static typing can accomplish is slow me down when I'm trying to bang out something. This is why Python (for instance) is loved by data scientists, researchers, and startups. And they're right to love it! Purely anecdotal, but I can accomplish more faster (from a clean slate) with a dynamic language like Python than I can with Haskell, Go, or Rust. The difference is small, but non-negligible. But static typing has a few key benefits: * No searching through comments for type constraints. * Better autocompletion. * Better compilation. * Better serialization/deserialization. I do think static typing pays for itself in the long term. Sometimes, we shouldn't care about that. Engineering means managing tradeoffs: short-term velocity vs long-term performance and maintainability?
- coldtea 6y ago>There is no limit on the number of problems easier to solve using dynamically typed languages. So, some examples? Also examples where "easier" is not just "you don't need to write types". That goes without saying...
- moocowtruck 6y agohow about using something like clojure.spec where you need it most to help make that long term payment?
- madmax96 6y agoIt's an interesting take. e.g. provide specs/types across module boundaries only. Gradual typing is certainly becoming popular. Meanwhile, statically typed languages are adopting type inference. Some people only write the types for the exports in their modules. The two worlds are coming closer. More statically typed languages are adding dynamic type information (like Go). More dynamically typed languages are supporting static type markup (like Python).
- ywei3410 6y agoThe auto-completion is purely Python's dynamic-dispatch problem though. Lisp has symbol-based auto-completion which doesn't suffer from the same issue (search is a different story!). This sounds terribly controversial, but I would love to know /when/ the static-typing pays off compared to a looser approach like sound-gradual typing (where you basically export types at a boundary and make sure that you don't violate those). I do wonder whether a better approach is to prove your code in some other language (say Z3, Agda, Coq) - then implement it in something else, making sure you can prove isomorphism. This has quite a few benefits; you're not tied to a constructive proof on the type-level ala Haskell, Rust, Go etc... and you can automate a large part of trivial proofs.
- coldtea 6y ago>1. You could use "reflection" or some dynamic feature to do this, but lose type-safety By using reflection you only lose type-safety for this particular function. With a dynamic language, you lose it everywhere. And it's still an one-liner or close in a language without much ceremony (e.g. not Java 1.5). Example implementation (pseudo-code): fun capitalize (o: object) -> [f.toUpper() for f in reflection.fields(o) if reflection.type(f) == "string"]
- iso8859-1 6y agoI reject the claim that it is reasonable to capitalize all the string fields of arbitrary objects. But it can still be done, like you mention, by using reflection. Now, you claim that it is unsafe. This is untrue, it depends how the reflection works. Even if it were unsafe, it would be no worse than in Python, where you get a TypeError or in JavaScript where you get undefined, which probably leads to a crash later. For an example of reflection which is safer than just a string-dictionary like JavaScript or Python, see GHC.Generics. It works by compile-time generating a type safe structure which is not just a dictionary. The function you want would have a signature involving this constraint, "Generic x => x -> x", which means it works for any "object" implementing the Generic interface. Now you may say "but I asked for a function that handles all objects", but I don't see the point. In statically typed languages you get an additional option of using generics when you want. It doesn't make sense to me to require all types to implement reflection when you don't actually need it everywhere.
- IshKebab 6y agoThat's not a very compelling example - in most statically typed languages the object field names are not actually stored in member, so it makes no sense to want to do runtime operations on them, because they don't exist by the time the code is compiled. That's why you find it hard to do in a compiled statically typed language - because it's not something that really makes any sense.
- yawaramin 6y ago> Let's say you want to write a function that can capitalize all the string fields in the object passed in. In a dynamic language, you could map over the values and apply capitalization trivially. It would be a one-liner. That's fair, but can you explain the context here? I.e. why are we trying to capitalize all the field names of a record object? This may be an 'XY' problem--you may be trying to accomplish some final goal and 'capitalize all the field names of a map' seems like an obvious intermediate step to you, while to a statically typed language programmer they may take a very different approach.
- boomlinde 6y ago> In reality, you probably wouldn't even try to write such a function in a typed language because of how awkward it is. In reality, you probably wouldn't because of how contrived and completely removed from any conceivably realistic practical goal this example is. In what situation would I actually need to solve this problem for every type in my program?