Contract Programming is a very nice way to prevent undetected failure, inspiring from Dlang here is a start of proposal :
A new compiler flag -contract
(or -debug
) , without this flag the compiler would just ignore contract related code
function myFunc(param: number): number
in {
assert(param > 0); // the assertion library is not part of typescript but any thirdparty
}
out (result) {
assert(result < 0);
}
body {
return -param;
}
would emit :
function myFunc(param) {
(function () {
assert(param > 0);
})();
var _$result = (function (param) {
return -param;
}).apply(this, arguments);
(function (result) {
assert(result < 0);
}).call(this, _$result);
return _$result;
}
respecting a D-like contract for class is challenging, especially rules about inheritance, and the outputed JS might become unreadable, here is a 'simplified' proposition without any inheritance logic.
class MyClass {
message: string = 'hello ';
invariant {
this.replaceMessage('test'); /// error invariant cannot call public member
assert(typeof this.message === 'string');
}
constructor(name: string)
in {
assert(typeof name === 'string');
}
//no out authorized for constructor
body {
this.message = this.message + name;
}
replaceMessage(message: string): string
in {
assert(message);
}
out (result) {
assert(result);
}
body {
this.message = message;
return this.message;
}
sayMessage() {
alert(this.message);
}
}
class ExtendedClass extends MyClass {
invariant {
assert(this.message.length > 0);
}
}
would emit
var MyClass = (function () {
function MyClass(name) {
//call precondition
(function (message) {
assert(typeof name === 'string');
).apply(this, arguments);
this.message = 'hello ';
this.message = this.message + name;
//call invariant
if (this.constructor.__$invariant) {
this.contructor.__$invariant.call(this);
}
}
MyClass.prototype.replaceMessage = function (message) {
//execute precondition
(function (message) {
assert(message);
).apply(this, arguments)
//execute invariant
if (this.constructor.__$invariant) {
this.contructor.__$invariant.call(this);
}
//execute body
var _$result = (function (message) {
this.message = message;
return this.message;
}).apply(this, arguments);
//execute invariant
if (this.constructor.__$invariant) {
this.contructor.__$invariant.call(this);
}
//execute out
(function (result) {
assert(result);
}).call(this, _$result);
return _$result;
};
MyClass.prototype.sayMessage = function () {
if (this.constructor.__$invariant) {
this.contructor.__$invariant.call(this);
}
//execute body
var _$result = (function () {
alert(this.message);
}).apply(this, arguments);
//execute invariant
if (this.constructor.__$invariant) {
this.contructor.__$invariant.call(this);
}
return _$result;
};
MyClass.__$invariant = function () {
this.replaceMessage('test');
assert(typeof this.message === 'string');
}
return MyClass;
})();
var ExtendedClass = (function (_super) {
__extends(ExtendedClass, _super);
function ExtendedClass() {
_super.apply(this, arguments);
}
ExtendedClass.__$invariant = function () {
_super.__$invariant.call(this);
assert(this.message.length > 0);
}
return ExtendedClass;
})(MyClass);
This is a lot of new syntax and emit. Is the idea that there'd be some useful static analysis done with the assertions? Or is it just sugar for precondtions(); try { body(); } finally { postconditions(); }
?
The idea is that those assertion would disappear for production code, and so is only executed during test stabilization like in D.
And yea I guess it opens the path for some static analysis.
Love CodeContracts, so definetely vote.
I really like the _idea_ of Code Contracts, but I question if the implementation fits as part of the TypeScript language itself.
:+1:
Is the idea that there'd be some useful static analysis done with the assertions?
No. D language style contracts in TypeScript is a runtime construct. Where the contracts would be compiled in using a debug flag, otherwise would be omitted entirely.
Or is it just sugar for
precondtions(); try { body(); } finally { postconditions(); }
?
Mostly. Throwing inheritance into the mix makes conditions combine in ways that are non-obvious (at least at first). The preconditions and postconditions can (read-only) reference the parameters. And the postconditions can (read-only) reference the result.
Having this feature would be a huge step towards facilitating design-by-contract in TypeScript. Definitely has to be part of the core language proper, and not as an add-on library.
Sounds like a nice idea, but agree with @david-driscoll that this doesn't seem a good fit with TypeScript - IMO it's more appropriate for JavaScript, or for people building very small libraries.
I don't like the verbose in {}, out {}, body {}
etc. which just makes reading the code difficult, and I cannot envisage our large code-base being sprinkled with these.
Some of the assertions are superfluous, for example:
class MyClass {
constructor(name: string) {
/*in {
assert(typeof name === 'string');
}*/
}
}
var myClass = new MyClass(10); // Error: Will only accept string in any case
There is no need to depend on this runtime assertion, when one gets it at compile time now with TypeScript.
It should be possible to write a test framework, without involving TypeScript, by using direct proxies that can then be dropped into the application at runtime in order to monitor and assert the behaviour of the various objects that make up the application.
Using proxies would be an interesting option. I know there has been talk of Reflection like information in TypeScript, if there was a command line option to emit those values, then a framework could be created to read the reflection information, and create the appropriate proxy assertions at runtime, and it would then be JavaScript specific vs TypeScript only.
It's not that I'm against Coding my Contract, it's actually something I really really like in C# (if only the cccheck was a little faster!)
I know there has been talk of Reflection like information in TypeScript, if there was a command line option to emit those values, then a framework could be created to read the reflection information, and create the appropriate proxy assertions at runtime.
Another option might be to define the requisite assertion in the JSDoc and reading that in order to create the runtime proxy:
class MyClass {
/** The myFunc calculation
* @param foo The foo number [ value > 0]
*/
myFunc(foo: number): number {
return 0;
}
}
This has the advantage of documenting the method, without cluttering up the implementation.
I really like this idea. And I like the syntax.
But if it's not a good fit for the language, you could still use Contract.require(condition) or similar constructs that are already in use in .NET and simply add something to the compiler that looks for this. And if done right, you even gain the static checking benefit. :)
I very much support this idea! :+1:
NoelAbrahams said...
I don't like the verbose in {}, out {}, body {} etc. which just makes reading the code difficult, and I cannot envisage our large code-base being sprinkled with these.
If Design-by-Contract facilities were baked into TypeScript, and your team does not want to use the DbC idiom, then you would at liberty not to use it.
It's not a "must use", it would be an language enabling paradigm that would be "opt in".
In the same way that C++ enables multi-paradigm programming: procedural, functional, object-oriented, and generic. And if your team did not like functional programming paradigm, it would not have to use the functional programming paradigm. (Note that C++ does not enable DbC paradigm.)
If Design-by-Contract facilities were baked into TypeScript, and your team does not want to use the DbC idiom, then you would at liberty not to use it.
Yes, of course. Everyone should be at a liberty to clutter up their code as they please.
I was merely stating my opinion, which is that TypeScript money could be spent more wisely.
There is no need to depend on this runtime assertion, when one gets it at compile time now with TypeScript.
For the sake of simple example I've gone with that kind of assertion, however in general you want test type of arguments but more some complex condition or state.
Instead of the in {} out {} body {}
syntax, I feel like this would be better as a separate type declaration:
class positiveNumber contractOf number {
contract isPositive() {
return this > 0;
}
}
class negativeNumber contractOf number {
contract isNegative() {
return this < 0;
}
}
class smallPositiveNumber contractOf positiveNumber {
contract lessThan1000() {
return this < 1000;
}
}
function myFunc(param: positiveNumber): negativeNumber
return -param;
}
This would allow you to use these contracts just by using the type wherever you'd like. And has the benefit of cleaning up the js code as well with some readable code:
var positiveNumber = (function () {
function positiveNumber() {
}
positiveNumber.isPositive = function (self) {
return self > 0;
};
return positiveNumber;
})();
var negativeNumber = (function () {
function negativeNumber() {
}
negativeNumber.isNegative = function (self) {
return self < 0;
};
return negativeNumber;
})();
function myFunc(param)
assert(positiveNumber.isPositive(param));
assert(smallPositiveNumber.isLessThan1000(param));
var _$result = (function (param) {
return -param;
}).apply(this, arguments);
assert(negativeNumber.isNegative(_$result));
return _$result;
}
Note: I use a new syntax contractOf so that you can cast a positiveNumber to number, and vice versa, e.g.:
var pos: positiveNumber = 5.34; //Could be checked at compile time
var num: number = pos;
pos = num - userInputNumber();
to this javascript:
var pos = 5.34;
var num = pos;
pos = num - userInputNumber();
assert(positiveNumber.isPositive(pos));
I feel like this syntax could be expanded to include the units of measure suggestion in #364, though I'm still processing my thoughts on that.
Then use something like grunt-strip to strip all Assert.* statements from production code.
Firstly this solution won't work with inheritance (that I can accept) but you would lose invariant (or have to manually check each tim for each method) and finally it will works with simple assertion, but if you do something like :
class MyClass {
method(arr: string[])
in {
arr.forEach((str) => {
assert(str);
assert(str[0] === 'a' || str[0] === 'b') ;
....
});
}
body {
...
}
}
there is no way that simply striping will work.
Native contract support in language such as D greatly improve the experience of developer that wish to follows the Design by Contract paradigm, and it's personally something that I wish to see natively supported by TypeScript. After it's only a matter of which direction the TypeScript team want to give to the language.
@dsherret The thing that using Asserts that get stripped the Asserts doesn't solve is if you have the same asserts in various places in the application. As in the example I have above, the contract for apositiveNumber
could be used in many places across the application, and it would be nice if tsc
could propogate those asserts (and compile time checks) across the entire application.
This suggestion is also possibly at odds with a couple of TypeScript design goals:
1 Exactly mimic the design of existing languages. Instead, use the behavior of JavaScript and the intentions of program authors as a guide for what makes the most sense in the language.
6 Provide additional runtime functionality or libraries. Instead, use TypeScript to describe existing libraries.
@NoelAbrahams Well, you can do something like my proposal in javascript now, but the TypeScript to generate it has compile errors:
TypeScript
class PositiveNumber {
constructor(private num: number) {
assert(num > 0);
}
valueOf() {
return this.num;
}
}
var posNum: PositiveNumber = new PositiveNumber(5);
var shouldBe10: number = posNum + 5; //Invalid '+' expression - types not known to support the addition operator.
var shouldBe5: number = Math.max(posNum, 4);
/*
Supplied parameters do not match any signature of call target:
Could not apply type 'number' to argument 1 which is of type 'PositiveNumber'.
Could not select overload for 'call' expression.
*/
JavaScript
var PositiveNumber = (function () {
function PositiveNumber(num) {
this.num = num;
assert(num > 0);
}
PositiveNumber.prototype.valueOf = function () {
return this.num;
};
return PositiveNumber;
})();
var posNum = new PositiveNumber(5);
var thisIs10 = posNum + 5;
var thisIs5 = Math.max(posNum, 4);
Additionally, the intuitive posNum += 5
doesn't do what you'd expect. You'd have to do posNum = new PositiveNumber(posNum + 5)
:+1:
Came here out of curiosity after viewing the discussion for a similiar feature in C# over @ Roslyn.
A similar syntax as is being proposed over there might work:
insert<T>(item: T, index: number)
requires index >= 0 && index <= this.count
ensures return >= 0 && return < this.count
{
return this.insertCore(item, index);
}
which still comes down to the same:
Array.prototype.insert = function(item, index) {
if(!(index >= 0 && index <= this.count)) {
throw "Failed requires.";
}
var __returnVal = this.insertCore(item, index);
if(!(__returnVal >= 0 && __returnVal < this.count)) {
throw "Failed ensures.";
}
}
or
Array.prototype.insert = function(item, index) {
Assert.isTrue(index >= 0 && index <= this.count));
var __returnVal = this.insertCore(item, index);
Assert.isTrue(__returnVal >= 0 && __returnVal < this.count);
}
Could decorators be used to support this? As suggested in the linked issue, something like:
@precondition("param > 0")
@postcondition("result < 0")
function myFunc(param: number): number {
return -param;
}
Now I don't have the experience to say but it looks as if something like this work would without any languages changes?
Perhaps you could even use proper expressions instead of string constants? Btw I'm just guessing here as I haven't taken the time to fully understand decorators but still interested in code contracts.
I love the idea, I've used CodeContracts in my C# projects for years but recently dropped it because the development is not as active as it should be (if at all now..) but really dislike the proposed syntax.
I really love the syntax proposed by @RichiCoder1 and iirc it's similar to SpecSharp.
Does the typescript team even feels favorable to the very concept of contracts ?
I feel this might become more and more popular thanks to people now being exposed to things like clojure.spec. To me, it seems contracts/specs/etc value really (only) shine when used together with automatic/generative testing. Having to go to the proper screen, play with it till we reach the right state to trigger the proper function, to finally get our contract assert code trigger is not good and barely a step up from dynamic programming (React likes do to a lot of these runtime assertions)
Also, there might be some overlap with other tickets about dependent typing. Both have the same end goal: Express value constraints, with types or not.
While I assume runtime assertions would be way easier to implement, I feel that dependent types would be a much superior alternative in the absence of generative testing.
@AlexGalays
To me, it seems contracts/specs/etc value really (only) shine when used together with automatic/generative testing.
If they will introduce contracts into the language then they _might_ provide static analysis but in case they won't then anyone else can pick it up and do it but first it needs to be formalized in the language.
@AlexGalays just to add more information, contract-based programming has existed in Eiffel for a very long time and that's a language that compiles to C. They provide different compilation options to check assertions and contracts at run-time. You can use contracts to generate tests and documentation, but run-time assertions are something I would highly recommend. You want to fail fast and visibly (even in user-facing applications).
In a way, TypeScript is doing this. StrictNullChecks for example will let you know upstream if you are going to cause a null reference. :)
@electricessence That's closer to the distinction between Type
and Maybe<Type>
(where the latter is defined as type Maybe<T> = T | void
). Constraints are different. There's a much greater difference between a sugared Type? = Maybe<Type>
and param: Type where param > 10
. Additionally, TypeScript retains an extraordinarily high bar on what features merit an actual emit. (Type-safe enums and namespaces hit that bar when they were first introduced, but integer casts haven't hit even close yet.)
As for where I stand, I'd prefer something that allows constraints to be verified at compile-time without an emit, but implementing it would be far from trivial best case scenario, and the compiler, from what I've gathered, is a massive hack in its current state.
@isiahmeadows I'm with you. I'm just happy to see it doing something similar at the moment.
Would love to see full contract capability.
Looking forward to it!
@nbransby Surely decorators can do the job, as can normal condition-exception pairs (@RichiCoder1 illustrates this in the comment above yours). But the key here, as I understand it, is to be able to have some static analysis on top of the contracts (hopefully by TypeScript itself, but not necessarily only this), for which it is useful to have a standardized syntax.
Just for reference. Contractual uses a compiler to generate the contracts. If compiler not used, the extra code remain as unused objects. (maybe those are eventually stripped by normal JS runtime or ts). See http://codemix.github.io/contractual/index.html#usage
The use-case for dbc for TypeScript is weak, IMHO, since TS does not pertain directly to runtime code. Seems more as a case for Behavior Driven Development => rules defined in Gherkin as business domain level rules. Just thinking out loud here; probably noise.
@josefbetancourt Most DBC implementations exist as a compile-time feature whether the ability to express the contracts is baked into the language and whether an analyzer is built-in to the compiler but it's definitely not a run-time feature so I'm not sure what you're on about but it shouldn't be any different for TypeScript.
@fdecampredon It's a long time since this feature request... do you know the current state of "design by contract" in TypeScript... maybe something as a third party library you could suggest?
@fdecampredon It's a long time since this feature request... do you know the current state of "design by contract" in TypeScript... maybe something as a third party library you could suggest?
I'd love to see a library that mimics the Preconditions
utility class from the Java library called Guava. Would need to be tailored a little bit to the language specifics, but for the most part it would be great just as is IMHO.
Been considering writing something like that myself for a long time, but time is always an issue of course.
Big thumbs up for this thread in general. 👍
@petermetz https://github.com/codemix/contractual
This is very much outside our modern design goals.
Most helpful comment
@fdecampredon It's a long time since this feature request... do you know the current state of "design by contract" in TypeScript... maybe something as a third party library you could suggest?