A core Python committer's (very shallow) thoughts on Dart
sayspy.blogspot.com
sayspy.blogspot.com
But, just like documentation, if it gets out of date you're really wonked.
I'd prefer something that is both useful as documentation and is used by the compiler (a la Haskell's type classes).
(I'm genuinely curious.)
Are people really going to run in checked mode to verify their code? Or they going to do what they do with compiler warnings and turn them off as soon as they see one? I'm sure there will be a million blog posts titled "Dart Best Practices" that will say "do not use checked mode, it slows down execution and prints confusing messages". Of course, any bugs in checked mode will mean people will need to get their production systems working by ignoring checked mode.
I guess... my gut tells me that you should either have types, or not have types. Being in the middle creates too many opportunities for cognitive dissonance, too many opportunities for sneaky bugs, and too many opportunities to keep having this debate. It's one of those things that seems really smart and cool that, on a practical level, will probably turn out to be a complete waste of time and a total distraction.
Summary
Gilad Bracha discusses Dart, its type system, interfaces, generics, ADTs without types, built-in factory support.
Yes, but it's not the same as outdated comments. A well featured optional type system will let you know that is happening. An out of date comment will just continue to deceive.
Or they going to do what they do with compiler warnings and turn them off as soon as they see one?
My advice, is not to work in such shops.
I guess... my gut tells me that you should either have types, or not have types. Being in the middle creates too many opportunities for cognitive dissonance
As if there's a lack of them on the ends of the spectrum compared to the middle. We will find out if it will be more of a mess, so many will have gut-calibration data.
The worlds collective programming experience doesn't really back that up. Almost every language drops (or makes optional) type support when constructs become too complicated, or they become so complicated no one can understand them.
Languages with the best type systems (OCaml) aren't particularly popular, while languages we think of as strongly typed (eg Java) have big backdoors to allow people to bypass the type system.
On the other side, weakly typed languages are adding typing-like features by integrating unit test facilities into the environment (which - optionally - catch many of the bugs typing can help with).
Like so many things, optional typing might seem impure, but often messy systems are the most robust.
Maybe it's my Java background coming through, but I like the idea of Factory constructors.
DI Frameworks were originally created to provide an alternative to Factories.
A classical, say Java or C# way will still need coupling to such a class. In dart, there is real decoupling going on.
Uh no it does not, it just needs a class. Unless what you mean by "a class instance" is "a class object". A factory method is a classmethod, not an instancemethod.
A factory method and a "factory constructor" need exactly the same thing: the class object.
> In dart, there is real decoupling going on.
In dart, there's mostly a bloody mess of 4 different constructors when all you need is a constructor and an initializer, as done in e.g. Ruby or Python. And these can be "regular" methods (respectively on the class and on the instance).
Conversely, you can also have an "overridden" constructor as in Javascript: an instance is built, the constructor function is called using the instance as its context, and if the constructor returns something that something is returned by `new` in stead of the original object.
This completely depends on your implementation. It's possible to implement it as instance method, or static method.
> Uh no it does not, it just needs a class.
Whether it be a static factory method or an instance method, fact is you need a reference to an implementation (class). In dart, you can do
List someListInstance = new List();
where List is an interface. There is none class needed in your consuming code, none. In C# or Java, this is impossible: You need _some_ class (whether it be a static method on it, or an instance method) to get a new instance of the interface.Named constructors felt very liberating when working with Dart.
new List.from([instance1, instance1]);
delivers a lot of clarity, while offering the promised decoupling by the GoF:> Define an interface for creating an object, but let the classes which implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.
(I don't know Dart, though)
It makes no sense, if you're doing that you've switched to full-blown factories (abstracts or builders), you're not using factory methods anymore.
> Whether it be a static factory method or an instance method, fact is you need a reference to an implementation (class). In dart, you can do
> List someListInstance = new List();
> where List is an interface. There is none class needed in your consuming code, none.
That's got nothing to do with factories, or interfaces.
> You need _some_ class (whether it be a static method on it, or an instance method) to get a new instance of the interface.
You always need a class, even in Dart there has to be a default List implementation of some sort which can be called (and has to be specified on the interface, it's not like you can even provide your own default implementation of a third party's interface). As to the calling code needing to know about that one concrete implementation:
abstract class Foo {
public static Foo foo() {
return new FooImpl();
}
public abstract void printFoo();
}
class FooImpl extends Foo {
public void printFoo() {
System.out.println("I am FooImpl");
}
}
class Main {
public static void main(String[] args) {
Foo foo = Foo.foo();
foo.printFoo();
}
}
Oh look at that, the calling code does not know anything about FooImpl.> Named constructors felt very liberating when working with Dart.
Yeah, that's so much more liberating than:
List.from([instance1, instance2]);
Wait, no it's not.> You always need a class
Nope. That's the whole point which I am trying to communicate: you do not need a reference to a class to get the instance of the interface from, as you confirm later on:
> As to the calling code needing to know about that one concrete implementation:
My personal feeling of liberation comes from the fact that the code is simpler and more clear. The non-coupling is nice, but can be achieved with dependency injection too: the point is the transfer of characters into a mental model which is more efficient with the named constructors/factory constructors.
Foo is an abstract class, which is the exact same thing.
> Nope. That's the whole point which I am trying to communicate: you do not need a reference to a class to get the instance of the interface from
Neither do you in the code I posted, can you bloody read?
> My personal feeling of liberation comes from the fact that the code is simpler and more clear.
You'll have to give actual examples of that, because I've not seen it so far.
> the point is the transfer of characters into a mental model which is more efficient with the named constructors/factory constructors.
This phrase doesn't even make sense, what "transfer of characters" are you talking about, and how is it more efficient for the user to type more? (named constructors only add ceremony to factory methods) (I'm not even going to talk about factory constructors again, they're a band-aid on the self-inflicted wound of stupid java-style constructors)
To whit: let's say you want to have an interface for associative arrays. Let's call it Map. Now let's say you want to provide a static method to create an instance of the default Map implementation (call it, say, HashMap). So you'd think about doing something like this:
interface Map { ... static defaultImpl() { .... } }
Except, interfaces can't have implementation in them. That would imply multiple inheritance (which languages like Dart and Java don't support).
Okay, so one workaround: use an abstract class:
abstract class Map { ... static defaultImpl() { .... } }
The only problem is that if you define Map as an abstract class instead of an interface, that means that all implementations of Map must extend Map. Given single inheritance, this means anything providing a Map-style interface can and must only extend from the base Map class.
So... Factory classes are there because of how Java treats interfaces and single inheritance.
http://discuss.joelonsoftware.com/default.asp?joel.3.219431
NB Factories are one of these things that seem like a good idea in theory, but often seem to end up with crazy levels of abstraction in practice.
"New layers, more layers, bigger layers, better layers, abstract layers, injected layers, factory layers, module layers, AbstractFactoryFactoryModuleBuilderInjector layers, layers upon layers within layers wrapped in layers, a glorious spire of layers to reach the heavens and bring renown to Babylon! Hellelujah!"
Essentially closures, curried functions, partial evaluated is the same thing: code that generate code.
I'm not a java developer
That doesn't make factories bad.
Better languages don't special-case the constructor instead (no `new` operator), the constructor is just a class method. Bam, "factory method" constructors out of the box and problem solved.
Does Python do that too?
Factories aren't common in Python, but they are used in exactly the same cases where they are used in Java (eg [1],[2],[3]). If you need to decide at runtime what object from an object hierarchy to create you use a factory. There's nothing inherently bad about that.
[1] http://www.linuxtopia.org/online_books/programming_books/pyt...
[2] http://stackoverflow.com/questions/8129018/factory-method-in...
[3] http://eikke.com/python-factory-like-type-instances/ (though I prefer the version in the comments here)
Factories are everywhere in Python because the default construction workflow goes through a bloody factory method.
> There's nothing inherently bad about that.
You may want to read my comment instead of inventing things I never wrote, because the comment you replied to didn't even remotely hint at factories being bad.
Oh, and the first two examples you provide are absolutely horrendous, it's not surprising they are used "in exactly the same cases where they are used in Java", because what you show there really is java code translated to Python.
Whereas the third one is something you can't do in Java: it factorizes the creation of a class through customization of the metaclass's standard creation protocol. The version in the comments overrides the creation of the instance (through, again, a completely standard override of Python's built in construction protocol), which is less efficient but doesn't require understanding metaobjects.
Or, perhaps more specifically, you can implement an interface without extending its default implementation.
As the article states, the default implementations are there more so that you can say "m = new Map()", instead of having to remember about this other thing called "HashMap".
A last method is much more intention revealing and easier to scan for me than negative indexes.
Usually is the dangerous word here. (Dangerous as in, "a little knowledge.")