Question

Being either static or dynamic should be something completely supported in the language. Static vs dynamic shouldn't be something that you have to turn on and off, switching between basically 2 languages.

I'm talking full blown mixed typing madness like this thing:

class MyClass {
  function myMethod(x: int, y: int){        # one parameter is typed, the other not
    return <cast_to_int> y.return_integer(x); #casting to guarantee the contract
  }    
}

MyClass static_obj = MyClass();  #statically typed instantiation;
var dynamic_obj = {};   #dynamically typed instantiation
dynamic_obj.return_integer = (function (x) {return x*2}) #dynamic method creation

static_obj.myMethod(3, dynamic_obj)     # This returns 6

dynamic_obj.return_integer = (function (x) {return x+1}); # dynamic member reassignment

static_obj.myMythod(3, dynamic_obj)   # this returns 4


static_obj.myMethod('asdf', dynamic_obj) # This can't compile, because of typing

# and also this crazy thing; Notice that the static interface of the method is respected
if (<user input> == 2){
    static_obj.myMethod = (function (x: int, y){return x + y.yet_some_other_method(x);})
}

# but when the static contract is not respected, it doesn't compile
static_obj.myMethod = (function (a, b, c) {return 'asdf'}) # Compile time error

I'm interested in this topic because I really like that API discoverability in static languages is great (thing i liked about Java, C# and ABAP for a while), but I also like testing stuff at run time, monkey patching, REPLs, reassignment, and crazy reflection magic (which I liked about JavaScript and Python).

I'm aware of Dart's static type checker, but that's not enough, because it provides no actual static guarantees.

I'm also not interested in type inferrence. I want true static running next to true dynamic behavior. I also am aware that I can use mapping types like python's dict, or any JS object, or Java's HashMap) to pass around data (or even functions), but Java's mappings can't carry methods in them, Python's dicts can't (out of the box) have methods in them, and even though JS simply laughs at any kind of static restrictions - adding methods at runtime that DO get access via the this keyword to the context object is something really cool (I know Python does it too, when adding functions on the class object, but NOT on class instances).

My curiosity was also sparked by this paper: Static typing where possible, dynamic typing where needed

And the API discoverability argument came from my own experience, but this paper seems to support it: http://personales.dcc.uchile.cl/~rrobbes/p/ICPC2014-idetypes.pdf

Was it helpful?

Solution

Yes. C# as of 4.0 is probably the most common example, with the dynamic keyword. There are likely other good examples that I am forgetting or don't know about.

OTHER TIPS

A great example of this is Dylan. You can use static and dynamic typing in Dylan, e.g.,

define method double(a :: <integer>) => (result :: <integer>)
    2 * a
end

or

define method double(a) => (result)
    2 * a
end

This extends to variables, etc. Another more mild example is REBOL, but only in its function definitions, e.g.,

double: func [a [integer!]] [a * 2]
double: func [a] [a * 2]

Function parameters are the only place in REBOL any kind of type checking (or declaration, for that matter) is permitted.

Classic Visual Basic and VBA has had this ability from day one.

VB.NET also had this ability from release (1.0) with the option to "switch it off" using Option Strict On statement at the top of the code file or project wide in the project properties. This doesn't actually switch it off as such it just won't compile a late binding statement when this is on.

C# eventually caught up some time later in version 4.0 with the difference that you have to "allow" it by using the dynamic keyword.

Java sort of has this with the Object class.

int myMethod(int x, Object y) {
  return x > 0 ? x : (int)y;
}

void go() {
  Object obj;
  if(Math.random() > 0.5)
    obj = 3;
  else
    obj = "hello";
  myMethod(-5, obj); // throws ClassCastException if obj is a String
}

In Java 8, lambda functions are introduced, so you can put functions inside maps, though it's a bit unwieldy:

Map myObj = new HashMap();
myObj.put("add",
          (BiFunction) (Object x, Object y) -> ((Number) x).intValue() + ((Number) y).intValue());
BiFunction addition = (BiFunction) myObj.get("add");
int apply = (int) (Number) addition.apply(3, 2.2);
Licensed under: CC-BY-SA with attribution
scroll top