JonathanK
JonathanK

Reputation: 867

Semantic Type Safety in Python

In my recent project I have the problem, that some values are often misinterpreted. For instance I calculate a wave as a sum of two waves (for which I need two amplitudes and two phase shifts), and then sample it at 4 points. I pass these tuples of four values to different functions, but sometimes I made the mistake to pass wave parameters instead of sample points.

These errors are hard to find, because all the calculations work without any error, but the values are totally meaningless in this context and so the results are just wrong.

What I want now is some kind of semantic type. I want to state that the one function returns sample points and the other function awaits sample points, and that I can do nothing that would conflict this declarations without immediately getting an error.

Is there any way to do this in python?

Upvotes: 2

Views: 795

Answers (2)

bruno desthuilliers
bruno desthuilliers

Reputation: 77892

Pyhon's notion of a "semantic type" is called a class, but as mentioned, Python is dynamically typed so even using custom classes instead of tuples you won't get any compile-time error - at best you'll get runtime errors if your classes are designed in such a way that trying to use one instead of the other will fail.

Now classes are not just about data, they are about behaviour too, so if you have functions that do waveform-specific computations these functions would probably become methods of the Waveform class, and idem for the Point part, and this might be enough to avoid logical errors like passing a "waveform" tuple to a function expecting a "point" tuple.

To make a long story short: if you want a statically typed functional language, Python is not the right tool (Haskell might be a better choice). If you really want / have to use Python, try using classes and methods instead of tuples and functions, it still won't detect type errors at compile-time but chances are you'll have less type errors AND that these type errors will be detected at runtime instead of producing wrong results.

Upvotes: 2

tamasgal
tamasgal

Reputation: 26259

I would recommend implementing specific data types to be able to distinguish between different kind of information with the same structure. You can simply subclass list for example and then do some type checking at runtime within your functions:

class WaveParameter(list):
    pass

class Point(list):
    pass

# you can use them just like lists    
point = Point([1, 2, 3, 4])

wp = WaveParameter([5, 6])

# of course all methods from list are inherited
wp.append(7)
wp.append(8)

# let's check them
print(point)
print(wp)

# type checking examples
print isinstance(point, Point)
print isinstance(wp, Point)
print isinstance(point, WaveParameter)
print isinstance(wp, WaveParameter)

So you can include this kind of type checking in your functions, to make sure the correct kind of data was passed to it:

def example_function_with_waveparameter(data):
    if not isinstance(data, WaveParameter):
        log.error("received wrong parameter type (%s instead WaveParameter)" %
                  type(data))
    # and then do the stuff

or simply assert:

def example_function_with_waveparameter(data):
    assert(isinstance(data, WaveParameter))

Upvotes: 5

Related Questions