World's most popular travel blog for travel bloggers.

[Solved]: What would dynamically-typed languages actually do if type enforcement was removed?

, , No Comments
Problem Detail: 

I program in Python, which is a well-known dynamically typed language. I understand dynamic typing to mean mainly that "operations" (in a loose sense) in the language are either allowed or denied (raise an exception) based on the type of their operands, and that this type-checking is deferred as long as possible. My question is this: if that is what a fair characterization of dynamic languages, what would happen if the run-time type checking was removed?

It seems to me that if you want to make a meaningful distinction between a dynamically typed language like Python and an untyped language, you would have to define what actually would happen in the untyped language in situations in which the type system of a dynamic language would take action. For example, in Python, if I attempt to subtract an Integer from a String, e.g., "spam" - 5, I receive a TypeError. If that's what makes Python dynamically typed, what would an "untyped Python" do in that situation?

Asked By : BlueBomber

Answered By : Gilles

Your characterization of dynamically typed languages¹ is broadly correct. However, it is somewhat incomplete. Types go beyond type checking: they also characterize values. In Python, this is a fundamental part of the language.

In Python, every value is an object, and the type of a value is for the most part determined by the methods it supports. This is known as structural typing, and especially when done dynamically as duck typing. The main job of the - operator is to invoke the method __sub__ on an object. It performs a few additional type checks, and you can explore what happens when those type checks are removed by calling __sub__ directly.

>>> (3).__sub__("a") NotImplemented >>> "a".__sub__(3) Traceback (most recent call last):   File "<stdin>", line 1, in <module> AttributeError: 'str' object has no attribute '__sub__' 

The type errors are actually coming from verifications performed by the - operator. When you get down to __sub__, what happens is up to the method provided by the object.

  • The object constructed by the literal 3 is a built-in integer; its __sub__ method performs case analysis on the type of the argument. The innards of that method do something like this:

    if the argument looks like an integer:     perform integer subtraction else if the argument looks like a floating-point number:     convert the integer to floating point     perform float subtraction … else: return NotImplemented 

    The fallback case is a design choice of the built-in __sub__ method. It doesn't do a dynamic type check with a boolean result, but a dynamic type analysis.

  • The object constructed by the literal "a" is a built-in string; it has no __sub__ method. There is no type check per se here. The runtime engine does check whether there is a __sub__ method, but only as part of locating it: there isn't a check operation that's not intrinsically part of locating the method.

Thus "untyped Python" is a difficult concept to define — you can't take out the types without taking out fundamental parts of the language. You could phrase the question differently: what if, say, the code of the __add__ method of a string ("a".__add__) was applied to the data of a built-in integer?

>>> int.__add__("a",1) Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: descriptor '__add__' requires a 'int' object but received a 'str' 

This here is an actual type check. If this type check wasn't performed, what would happen would depend on the implementation. In a typical implementation, the code of the __add__ method for integers would attempt to access the object "a" as if it was an integer. Depending on the exact layout of objects in memory, it might do things like:

  • treat "a" as the integer 97 (because it's reading the same bytes and interpreting them differently);
  • interpret a location in memory as a pointer to an address, and operate on a bunch of bytes that happen to be present at that address, and thus construct a bogus integer as a result;
  • interpret a location in memory as a pointer to an address, and trigger a page fault because this address is not mapped in the calling process, resulting in the process dying of a segmentation fault;

In general, what happens on a typical computer when you remove type checks (static or dynamic) is undefined behavior. Eventually a bunch of bytes is interpreted in a way that's unrelated to the way it was constructed, which can lead to anything: a wrong result (because the bytes happen to mean something), a segmentation fault or other crash (because the bogus data leads to attempting to access a memory address that isn't mapped, or to execute data as code which may contain an invalid instruction), weird things happening (because the bogus data leads down a code path that has nothing to do with what the program should have been doing), etc. In C (a language which has no strong typing, meaning that the programmer can easily lie to the compiler about the type of objects), undefined behavior is a fact of life, and it famously can do anything including making daemons fly out of your nose (most computers fortunately lack the requisite hardware).

¹ Not "dynamic languages", which I don't recommend using as it's a lot fuzzier.

Best Answer from StackOverflow

Question Source : http://cs.stackexchange.com/questions/17987

0 comments:

Post a Comment

Let us know your responses and feedback