Duck Wrapping
brehaut.net
brehaut.net
So the difference is not that the type system would catch this sort of behavior or even that it would prevent it--the difference is that it wouldn't arise in the first place. Sure, this is more a difference of perspective than of actual behavior or features, but I think it's incredibly important nonetheless.
Thinking about types in this different way is actually quite a deep topic; I should write a blog post about it for that blog I keep on meaning to start :P. One day. At the very least, writing it all down would help me get my own thoughts in order.
map :: [a] -> (a -> b) -> [b]
In an implementation of map with this signature, the only way to get a list of b's is to use the function passed in. So, there's no way to do the array unwrapping shenanigans from the js example.
Or perhaps the program wouldn't even get written in the first place. The problem I have with straight jacket languages, I have to think long and hard about how to do something that the type system doesn't allow easily, especially when you consider all the premature commitments being made. You can argue that this is good, that the program will be more robust for it, but...often worse is better.
Can you give an example please because I'm struggling to think of one aside working with dates and time but those can be a pain on loosely typed languages as well (Perl, I'm looking at you).
I like static typing, I program in C#, but I use escape hatches a lot in my designs. Type systems just can't be expressive enough (even say Scala).
I will concede that you've probably written more sophisticated routines than I so it may just be a case that I've not ran into problems because I've not needed to run into problems (if that makes any sense).
A good enough type system you will be able to express abstractions so powerful that it turns the "straitjacket" into a suit of power armour. Instead of restricting the programmer, a good type system like Haskell's allows you to express your intent and program with certainty that many errors (like forgetting to handle an exception) are simply impossible.
There are also some things that are very cumbersome to write in dynamic languages. For example in Python it is a complete pain to write code that is datastructure-agnostic. A while ago I was working on some code where I had nested dictionaries with lists in them that contained single values and more lists/dictionaries, and found myself wanting to transform all the lists inside the thing in a certain way. In Haskell, this would've been trivial using the fmap function (type f a -> (a -> b) -> f b) which is a generalized map that works for any functor... The python solution ended up being a fragile hack of manual type checks and dispatch, since there is no uniform interface that all the data structures can implement.
I feel like dynamic programming languages are a good solution for prototyping and small programs/modules (eg. UI and scripting systems), but as systems grow larger, the amount of things you have to worry about grows exponentially, and a type system (+ immutability) helps keep it all together by minimizing the amount of parts that a change can affect.
Don't get me wrong, I'm not against loosely typed languages (eg in Perl it's very handy being able to use strings and integers as booleans), but that example you've given would scare me in any language as you shouldn't be making any assumptions about data unless the program generated that data itself (and even then, I'd still run a few checks if just to catch unconsidered exceptions / security vulnerabilities)
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-}
class Concatable a b where concat' :: a -> b -> a
instance Concatable [a] a where concat' l xs = l ++ [xs]
instance Concatable [a] [a] where concat' l xs = l ++ xs
a :: [Int] a = [1,2,3]
b :: Int b = 4
c :: [Int] c = [4]
-- Main> concat' a b
-- [1,2,3,4]
-- Main> concat' a c
-- [1,2,3,4]
Couldn't agree more that this is bad practice!
http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_c...
I don't think magic like this is out of place with JS; that's the zen of the language. Similarly for Ruby. Whereas in Java or Python, it would be out of place. Now you might use that as an argument against JS, but that's a separate debate.
"This is annoying at the level of Arrays, but gets more difficult with more complex types, and function interactions. The recent brouhaha around the Promise/A+ highlights one such example: It is difficult to return a Promise of a Promise as a value from onFulfilled because then duck-wraps the return value as described in the Promise Resolution Procedure"
Could anyone share a pointer to this brouhaha around the Promise/A+ [spec, I assume]?