Earlier quoted context omitted.
> Sure, but my point is that any nontrivial property requires the programmer to write difficult formal mathematical proofs which is an activity completely unlike what you see in mainstream strongly typed languages (e.g. Haskell, OCaml). So don't write the proofs then. Dependently typed languages don't require you to write proofs; they give you the ability to if you choose. Considering that it's impossible to write su…
> Considering that it's impossible to write such proofs in OCaml or Haskell, it seems strange to complain that they're hard to write in a dependently typed language. My sole point is that when I see articles on here about dependently typed languages, the issue of how the proofs are generated and the challenges involved in doing this is overlooked almost every time. I think it's important these challenges are highligh…
Types
181–190 of 198 posts
Re: Types
#182Earlier quoted context omitted.
Some subclasses can be safely used as subtypes. For example, those that meet the following two conditions: (0) Not directly mutating superclass fields. (Reading them is fine.) (1) Not overriding non-abstract methods of the superclass.
If classes are types, subsclasses should be subtypes -- so the above restrictions should just be applied to subclass relationships. One could also have an non-subclassing mechanism of implementation sharing, that might be declared something like this: class Related does (method1, method2) like Base; or class Related does all except (method3) like Base;
Re: Types
#183Earlier quoted context omitted.
If classes are types, subsclasses should be subtypes -- so the above restrictions should just be applied to subclass relationships. One could also have an non-subclassing mechanism of implementation sharing, that might be declared something like this: class Related does (method1, method2) like Base; or class Related does all except (method3) like Base;
That syntax is too heavyweight (IMO). AFAICT, most of the time, when people use inheritance, they don't want to define perfect subtypes. They just want to reuse as much already implemented behavior as possible.
I'd be fine with something more compact for the default case of "steal all behavior except what is explicitly overridden", such as:
class Related like Base;Re: Types
#184Earlier quoted context omitted.
That syntax is too heavyweight (IMO). AFAICT, most of the time, when people use inheritance, they don't want to define perfect subtypes. They just want to reuse as much already implemented behavior as possible.
> That syntax is too heavyweight (IMO). I'd be fine with something more compact for the default case of "steal all behavior except what is explicitly overridden", such as: class Related like Base;
(1) Do you think there would still be a use case for “extends”? If not, I'd rather drop it as well.
Re: Types
#185Earlier quoted context omitted.
That syntax is too heavyweight (IMO). AFAICT, most of the time, when people use inheritance, they don't want to define perfect subtypes. They just want to reuse as much already implemented behavior as possible.
> That syntax is too heavyweight (IMO). I'd be fine with something more compact for the default case of "steal all behavior except what is explicitly overridden", such as: class Related like Base;
Re: Types
#186Earlier quoted context omitted.
> That syntax is too heavyweight (IMO). I'd be fine with something more compact for the default case of "steal all behavior except what is explicitly overridden", such as: class Related like Base;
(0) Do you have a use case for cherry-picking which methods are inherited? If not, it seems like too much complexity for me. (1) Do you think there would still be a use case for “extends”? If not, I'd rather drop it as well.
The most obvious is that it makes intent explicit in the case of multiple similarity (I prefer "similarity" to "inheritance" for non-subtyping implementation reuse.)
It might in some cases make sense to do this on an interface rather than (or in addition to) single method level; there's probably a lot to work out in the ergonomics of non-subtyping implementation reuse.
> Do you think there would still be a use case for “extends”?
Sure, classical subclassing (subtyping with implementation sharing) remains an important use case. It might be desirable to statically verify certain guarantees (some have been suggested in at least one subthread of this thread by another poster) to assure that the subtyping is reasonable, but even without such verification the use case remains important.
Re: Types
#187Earlier quoted context omitted.
(0) Do you have a use case for cherry-picking which methods are inherited? If not, it seems like too much complexity for me. (1) Do you think there would still be a use case for “extends”? If not, I'd rather drop it as well.
> Do you have a use case for cherry-picking which methods are inherited? The most obvious is that it makes intent explicit in the case of multiple similarity (I prefer "similarity" to "inheritance" for non-subtyping implementation reuse.) It might in some cases make sense to do this on an interface rather than (or in addition to) single method level; there's probably a lot to work out in the ergonomics of non-subtypi…
Keep in mind that similarity is explicitly intended to be a quick-n-dirty form of code reuse. If the programmer has enough time to refactor the code, he or she should probably factor out the common parts, and then use proper (subtyping) inheritance. In view of this, I don't think making similarity overly complicated is a good idea.
> Sure, classical subclassing (...) remains an important use case. (...) even without such verification the use case remains important.
It's precisely the lack of such verification that destroys the guarantees you can extract from Liskov's substitution principle.
Re: Types
#188Earlier quoted context omitted.
> Do you have a use case for cherry-picking which methods are inherited? The most obvious is that it makes intent explicit in the case of multiple similarity (I prefer "similarity" to "inheritance" for non-subtyping implementation reuse.) It might in some cases make sense to do this on an interface rather than (or in addition to) single method level; there's probably a lot to work out in the ergonomics of non-subtypi…
> The most obvious is that it makes intent explicit in the case of multiple similarity Keep in mind that similarity is explicitly intended to be a quick-n-dirty form of code reuse. If the programmer has enough time to refactor the code, he or she should probably factor out the common parts, and then use proper (subtyping) inheritance. In view of this, I don't think making similarity overly complicated is a good idea.…
I do see the attraction of the idea that all implementation sharing ultimately reflects something that can be expressed through a subtyping hierarchy adhering to the LSP, but I'm not 100% convinced that it is the case. Absent certainty on that point, I'd like to have a model of similarity that is workable when viewed as an ultimate, rather than interim, model.
Also, I think that this kind of explicitness (with similar syntax) is desirable for subtyping inheritance in languages that support multiple inheritance, so it keeps similarity in line with inheritance, with the distinction only in the relationship being expressed (so, while it may make similarity more complex, it keeps the whole language more simple but explicit.)
> It's precisely the lack of such verification that destroys the guarantees you can extract from Liskov's substitution principle.
I agree that static verification of sanity in subtyping inheritance reduces the problem of LSP violations (as, frankly, does non-static verification, such as testing frameworks using subtype relationships to automatically apply tests for supertypes to subtypes.)
The degree and type of verification (as well as other details like cherrypicking and support for multiple similarity) that is appropriate for these type of things really depends on the language. Extending Perl or Python (dynamic languages with multiple inheritance) to support similarity alongside inheritance is probably going to favor different tradeoffs than extending Java (static with single inheritance) to support similarity.
Re: Types
#189Earlier quoted context omitted.
Some subclasses can be safely used as subtypes. For example, those that meet the following two conditions: (0) Not directly mutating superclass fields. (Reading them is fine.) (1) Not overriding non-abstract methods of the superclass.
If classes are types, subsclasses should be subtypes -- so the above restrictions should just be applied to subclass relationships. One could also have an non-subclassing mechanism of implementation sharing, that might be declared something like this: class Related does (method1, method2) like Base; or class Related does all except (method3) like Base;
Disagree. C++ added private inheritance for a good reason. There are scenarios when you want to inherit part of an implementation, but override some of the behaviour for code reuse without inheriting any kind of subtyping relationship.
There are also scenarios where you want to declare a subtype without inheriting any parent behaviour.
So ultimately subtyping is distinct from subclassing.
Re: Types
#190Earlier quoted context omitted.
> If a type couldn't be regarded as a collection of values in a strict language, then induction on datatypes would simply be unsound. Just because induction on some types is sound, does not entail that induction on all types is sound. Indeed it's not in general, even though it may be in specific languages.
(0) I didn't say all types. I said datatypes. (1) Induction on datatypes is a powerful tool for reasoning about programs in strict languages, and it's only possible when you regard datatypes as collections of values.