5 ms·
> This is especially true when your system is interacting with external data - like user input and a database. I did C# and Java for years. These interactions a
by seanwilson 9y ago
> This is especially true when your system is interacting with external data - like user input and a database. I did C# and Java for years. These interactions are, at best, painful with static languages.
Why? I find when you're importing external data or user input, that's exactly where you want strong types as that's the most likely place unexpected values are going to be generated (e.g. unexpected null values, string instead of an array).
- junke 9y agoStrong types, not necessarily static ones.
- latch 9y agoI don't disagree. It's just more tedious in static languages. Let's say we're doing a user registration. In most dynamic languages the JSON body will get parsed into a map. Excuse the fat controller and pseudo-language, but it'll end up looking something like: func create(conn, params) do if not Validator.is_email?(params["email"]) do return error(conn, "email is not valid") end if not Validator.min_length?(params["password"], 10) do return error(conn, "password must be 10 or more characters") end create_user(params) true end In Go, if you want this nice and typed, you'd add a RegistrationInput struct with the field mapping tags: type RegistrationInput struct { Email string `json:"email"` Password string `json:"password"` } Map the user's input to the structure, handling the error: var input RegistrationInput if err := json.Unmarshal(req.body, &input); err != nil { ... } And then write the exact same validation checks. What safety does Go's version buy you?
- Pxtl 9y agoIn C# MVC, the JSON gets deserializrd into a tree of statically-typed objects you declared beforehand. Any malformations of the JSON are an error.
- mercurial 9y agoWell, the dynamic version won't complain until runtime the day you mix up the order of your parameters and invoke "create(params, conn)", for instance. Besides, you can make it statically impossible to generate an invalid user object with a static language. In a dynamic language, an invalid user object is just an assignation away. Now, if we are talking about error handling, the way it is done in Go is not particularly representative. Most static languages would go with exceptions (or maybe checked exceptions in Java). Haskell/Rust/Scala would probably go with a Result type, and then it's more a question of the language giving you the tools to propagate the errors and wrap them (Rust with error-chain is excellent at this kind of thing).
- hota_mazi 9y agoYour example actually illustrates why dynamically typed languages should be avoided in general, especially when manipulating data coming from outside. Your code starts by making a few checks on the shape of the data you're receiving and failing earlier if some conditions are not met. Great. Once these checks are cleared, you now know that you can materialize an object with valid values in it, something the rest of your business code will be able to manipulate. So you instantiate that new object, return it and... all the knowledge about the shape of that data is lost. The only thing your callers will see is an Object and zero information about what operations or fields are available on this object. They'll have to guess. With a statically typed language, you don't have such a problem. You have asserted all these properties about the data that came in, you know exactly the class of the object you are creating, why forget all this precious information that will keep your code robust? In my experience, dynamically typed languages are at an evolutionary dead end and offer close to zero advantages over modern statically typed languages (e.g. Kotlin, Swift).
- harpiaharpyja 9y ago> Once these checks are cleared, you now know that you can materialize an object with valid values in it, something the rest of your business code will be able to manipulate. So you instantiate that new object, return it and... all the knowledge about the shape of that data is lost. I'm not really seeing how that necessarily falls out of the example given by GP. Could you go into that in more detail? Is there something preventing create_user(params) from emitting an object with a well defined interface?
- hota_mazi 9y agoThat function does create an object with a well defined interface, but because you are using a dynamically typed language, that object has the type "Object" (or Any, or whatever the mono type of that language is). If you call that function, you have no idea what the type of that object is. Only the function knows it and that information is lost as soon as the function returns.
- 9y ago
- seanwilson 9y ago> What safety does Go's version buy you? A statically typed version guarantees you haven't made some fundamental mistakes and enables automatic refactoring. Say we wanted to change an ID field from being a string to an int later in development for example. You've now got to hunt around all your files making sure the right type is being used. It feels incredibly primitive when you need to do this manually or have to rely on an exhaustive and annoying to maintain test suite for this.
- jasonkostempski 9y agoNo matter where the data comes from, there's so much more validation to be done that types can't handle. Why should validation concerns be split up?
- Ar-Curunir 9y agoIt's one less thing to worry about, and cut out some tedious overhead for the developer?
- jasonkostempski 9y agoBut the way it's done in static languages, it's one more thing you have to worry about constantly, even when it's not a real concern. And when you need to parse external data, all you get for free is ugly exceptions that you have to decipher to construct a user readable error.
- sametmax 9y agoMost modern dynamic languages have strong types. In Python you will get a TypeError if you try to add a string and an int or use > on a tuple and a dict. As for data validation, the hard part of it is not checking type but that the value is safe and coherent. And dynamic languages excel at that because they make complex declarative schema descriptions easy while powerful. See marshmallow for Python: https://marshmallow.readthedocs.io/en/latest/ https://marshmallow.readthedocs.io/en/latest/ It will validate everything, including nested recursive data with cross references in fields and a need for sanitation and casting. But you don't need a lot of code to do so. Static languages are good to enforce safe practices at scale . That's why they are popular in big IT structures. Dynamic languages are fantastic when you have a lot of external data manipulations. Hence their popularity for the Web, banking, biology, geography, etc.
- fnord123 9y ago> Most modern dynamic languages have strong types. In Python you will get a TypeError if you try to add a string and an int or use > on a tuple and a dict. >>> (1,2) > {1: 2} True >And dynamic languages excel at that because they make complex declarative schema descriptions easy while powerful. Marshmallow looks like it works the same way as existing systems in statically types languages. e.g. Serde in Rust: https://serde.rs/ https://serde.rs/ This validates at compile time.
- nooorofe 9y agoIn [60]: (1,2) > {1: 2} --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-60-f9d83a4c8f73> in <module>() ----> 1 (1,2) > {1: 2} TypeError: '>' not supported between instances of 'tuple' and 'dict'
- nicwolff 9y agoHe means Python 3.
- sametmax 9y agoI said "modern". Python 2 is not modern. Python 3 is. And the keyword in my schema validation sentence is "easy". I love rust, but a low level language cannot be compared in productivity to a high level language for this stuff. They are much, much easier. That's the whole purpose. You trade easiness for rigor.
- dbattaglia 9y agoCouldn't agree more. In my current life as a Ruby dev I've found the dry-struct (http://dry-rb.org/gems/dry-struct/ http://dry-rb.org/gems/dry-struct/) library a huge help in getting some level of sanity when dealing with converting inputs to data types. It also helps being able to reason about the inputs structure outside of just looking at some hash field indexing at time of use.