No, dynamic type systems are essentially no more open

The holy wars on the Internet about type systems continue to suffer from the widespread myth that dynamic type systems are inherently better suited for modeling subject areas of the “open world”. Usually the argument is: the purpose of static typing is to capture all entities as accurately as possible, but in the real world this is simply inconvenient. Real systems should be loosely coupled and as little as possible tied to the presentation of data, so dynamic typing leads to a more stable system as a whole.



This story sounds convincing, but it's not true. The mistake in such reasoning is that static types are not intended to “classify the world” or determine the structure of each value in the system. The reality is that static type systems allow you to specify exactly how much a component should know about the structure of its input data, and, conversely, how much it does not know. In practice, static type systems perfectly process data with a partially known structure, as well as being able to make sure that the application logic does not accidentally assume too much about the data.


Two lies about types


I have long wanted to write an article on this topic in a blog, but the last impetus for this decision was misinforming comments in response to my previous article . In particular, two comments particularly caught my attention, the first of which was published on / r / programming :


Strongly disagree with the post [...], which promotes a completely confused and static view of the world. It is assumed that we can or should theoretically establish what exactly is an “acceptable” input on the border between the program and the world, thus introducing a feeling of strong connectivity to the whole system, and then a mismatch of any scheme automatically leads to a program malfunction.
, , . JSON , . , . […] « » , .

, , , , . , - , , ? , , .


Hacker News :


, , pickle.load()?

, , , . , , .


, , . , , : . , ; , .


,


: , , , , ! , . , .


. , , . (payload), . , - , JSON EDN.


, , :


{
  "event_type": "signup",
  "timestamp": "2020-01-19T05:37:09Z",
  "data": {
    "user": {
      "id": 42,
      "name": "Alyssa",
      "email": "alyssa@example.com"
    }
  }
}

signup- . , . JavaScript, :


const handleEvent = ({ event_type, data }) => {
  switch (event_type) {
    case 'login':
      /* ... */
      break
    case 'signup':
      sendEmail(data.user.email, `Welcome to Blockchain Emporium, ${data.user.name}!`)
      break
  }
}

, Haskell? , Haskell, , , :


data Event = Login LoginPayload | Signup SignupPayload
data LoginPayload = LoginPayload { userId :: Int }
data SignupPayload = SignupPayload
  { userId :: Int
  , userName :: Text
  , userEmail :: Text
  }

instance FromJSON Event where
  parseJSON = withObject "Event" \obj -> do
    eventType <- obj .: "event_type"
    case eventType of
      "login" -> Login <$> (obj .: "data")
      "signup" -> Signup <$> (obj .: "signup")
      _ -> fail $ "unknown event_type: " <> eventType

instance FromJSON LoginPayload where { ... }
instance FromJSON SignupPayload where { ... }

handleEvent :: JSON.Value -> IO ()
handleEvent payload = case fromJSON payload of
  Success (Login LoginPayload { userId }) -> {- ... -}
  Success (Signup SignupPayload { userName, userEmail }) ->
    sendEmail userEmail $ "Welcome to Blockchain Emporium, " <> userName <> "!"
  Error message -> fail $ "could not parse event: " <> message

, (, , ). . , Reddit, , Haskell , ! Event, . , ? .


, JavaScript . , switch . , JavaScript . , .


, , . Event, , handleEvent. JavaScript, , :


const handleEvent = ({ event_type, data }) => {
  switch (event_type) {
    /* ... */
    default:
      throw new Error(`unknown event_type: ${event_type}`)
  }
}

, . , , . , , Haskell:


handleEvent :: JSON.Value -> IO ()
handleEvent payload = case fromJSON payload of
  {- ... -}
  Error _ -> pure ()

- «, », , . , ( ) . , ! , .


: Event Haskell « », , . , , . , , , .


, , , :


  • Haskell, . , , timestamp, . , , , , , !


  • , , Haskell userId SignupPayload, . , (, , userId ), ; , , , .


  • , , (shotgun parsing), , .



, , , , , . , , . , , , , , , .


JavaScript , Haskell: , JSON event_type «» signup data.user.name data.user.email. ! , JavaScript , . , ; , , - .



, , , , .


, , , - -. , , . , . JavaScript :


const handleEvent = (payload) => {
  const signedPayload = { ...payload, signature: signature(payload) }
  retransmitEvent(signedPayload)
}

( signature JSON), , . , ?


, : , . Haskell:


handleEvent :: JSON.Value -> IO ()
handleEvent (Object payload) = do
  let signedPayload = Map.insert "signature" (signature payload) payload
  retransmitEvent signedPayload
handleEvent payload = fail $ "event payload was not an object " <> show payload

, , JSON.Value. Event — JSON , , .


: , JSON- ( -), - JSON, - . , , , , . .


, , Haskell, JavaScript! JavaScript handleEvent ( JSON ), , , , spread- :


> { ..."payload", signature: "sig" }
{0: "p", 1: "a", 2: "y", 3: "l", 4: "o", 5: "a", 6: "d", signature: "sig"}

, . , . «» JSON Object, . -, , .




, . , API, , , UUID. «, » , API Haskell UUID:


type UserId = UUID

, Reddit, , ! API , UUID, , . UUID , , , ! , ?


, — . , — . , UserId — :


newtype UserId = UserId Text
  deriving (Eq, FromJSON, ToJSON)

, UUID, UserId, , Text. ( , ), UserIdFromJSON. , , UserIdUserId ToJSON. : .


, , . UserId , UserId .


1

, FromJSON UserId, , , fromJSON . , - . , , … UserId. , , ( , , , ).


— , . , , , .


-


, , , , , . pickle.load() Python? , , Python. pickle.dump(), pickle.load().


, , pickle.load(), — , pickle.dump(). , , . , , , .


, JSON, , pickle Python Python , . ? , , pickle.load(). , :


def load_value(f):
  val = pickle.load(f)
  #  -  `val`

, val , , , , , - . - - , , pickle.load(f) , , val!


, , , val val.foo() , . Java, val — , :


interface Foo extends Serializable {
  String foo();
}

, pickle.load() Java:


static <T extends Serializable> Optional<T> load(InputStream in, Class<? extends T> cls);

, , pickle.load(), Class<T> . Serializable.class , . : , -, - , ! , , JSON-.




Haskell? — serialise, API, , Java, . API , Haskell JSON, aeson, , , JSON Haskell — - - , -.


, , pickle.load(), . , . - , , , , . , (, REPL ), , .


. , , , , - , «» , , . , , , , , .


. , , , ( ). , , «» .


: ,


: . , , , , , .


, , . -, - (nominal typing). , , , , . , . , .


, , , , . , , -, , ( ).


. JavaScript Clojure - , - , . ( ) .


, , - , , . ( ) , (nominal typing). , ; (boilerplate).


, , . , , , . , :


  1. , , , , . ( ), : , .


  2. , , - . , , , . , .



Python, , , , TypeScript, , . , . - Clojure — , - — , - Clojure, - .


, : TypeScript, Flow, PureScript, Elm, OCaml Reason, . — Haskell, ; Haskell ( , ) .


2

, Haskell .


, Haskell , ? , ; Haskell, , . Haskell, , . , Haskell, , , . ( , , Haskell!)


: , , , . , , , . — , , , , . .

Source: https://habr.com/ru/post/undefined/


All Articles