Topik opsi dalam pemrograman menyebabkan banyak kesulitan dalam pemahaman, bagi saya itu adalah masalah yang tidak selalu metafora yang berhasil diambil sebagai penjelasan - wadah.
Saya harap saya dapat menjelaskan topik ini dari sudut pandang yang berbeda menggunakan metafora "tugas" dalam konteks lambdas.
Mengapa varians ini dibutuhkan sama sekali?
Secara umum, Anda dapat hidup tanpa variasi dan memprogram dengan damai, ini bukan topik yang penting, kami memiliki banyak contoh bahasa pemrograman di mana kualitas ini tidak tercermin.
Co-variance adalah tentang tipe data dan kontrolnya oleh kompiler. Dan tepatnya dari tempat ini kita perlu memutar kembali dan mengatakan tentang tipe data dan mengapa kita membutuhkannya.
Kilas balik ke jenis
Tipe data sendiri juga bukan topik yang sangat penting, ada bahasa di mana tipe data tidak terlalu dibutuhkan, misalnya assembler, brainfuck, REFAL.
Dalam REFAL atau assembler yang sama, sangat mudah untuk membingungkan jenis variabel, dan sangat mudah, misalnya, untuk mengasumsikan bahwa saya akan mengurangi baris lain dari satu baris, hanya salah ketik, tidak ada niat jahat.
Dalam bahasa yang diketik, kompiler akan melihat kesalahan ketik ini dan mencegah saya mengkompilasi program, tetapi ... misalnya JS
> 'str-a' - 'str-b'
NaN
JS (JavaScript) Tenang kode ini, mereka akan memberitahu saya bahwa ini bukan bug, ini adalah fitur , ok, katakanlah, maka saya akan mengambil Python
>>> 'str-a' - 'str-b'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'
Atau Jawa
jshell> "str-a" - "str-b"
| Error:
| bad operand types for binary operator '-'
| first type: java.lang.String
| second type: java.lang.String
| "str-a" - "str-b"
| ^---------------^
, - .
, .
, , , , .
: , Groovy
groovy> def fun1( a, b ){
groovy> return a - b
groovy> }
groovy> println 'fun1( 5, 2 )='+fun1( 5, 2 )
groovy> println "fun1( 'aabc', 'b' )="+fun1( 'aabc', 'b' )
groovy> println 'fun1( [1,2,3,4], [2,3] )='+fun1( [1,2,3,4], [2,3] )
fun1( 5, 2 )=3
fun1( 'aabc', 'b' )=aac
fun1( [1,2,3,4], [2,3] )=[1, 4]
JS
> fun1 = function( a, b ){ return a - b }
[Function: fun1]
> fun1( 5, 2 )
3
> fun1( 'aabc', 'b' )
NaN
> fun1( [1,2,3,4], [2,3] )
NaN
.
, , - , .
/ - .
, .
- .
TypeScript
function sub( x : number, y : number ) {
return x - y;
}
console.log( sub(5,3) )
JS.
function sub( x : number, y : number ) {
return x - y;
}
console.log( sub("aa","bb") )
- :
> tsc ./index.ts
index.ts:5:18 - error TS2345: Argument of type 'string' is not assignable
to parameter of type 'number'.
5 console.log( sub("aa","bb") )
~~~~
Found 1 error.
sub
, , number
.
TypeScript (tsc
).
,
ฬ โ () , .
A โ G โ A A. f A B G, a โ A g โ G f(a)=f(g(a)).
, :
- , .
, JS
> fun1 = function( a, b, c ){
... let r = b;
... if( a ) r = c;
... return r + r;
... }
[Function: fun1]
> fun1( 1==1, 2, 3 )
6
> fun1( 1==1, "aa", "b" )
'bb'
> fun1( 1==1, 3, "b" )
'bb'
> fun1( 1!=1, 3, "b" )
6
> fun1( 1!=1, {x:1}, "b" )
'[object Object][object Object]'
r - string number , fun1 , .
r. r .
r :
let r = b
, r , b.
r = c
, r , c.
, .
, :
> fun1 = function( a, b, c ){
... if( typeof(b)!=='number' )throw "argument b not number";
... if( typeof(c)!=='number' )throw "argument c not number";
... let r = b;
... if( a ) r = c;
... return r + r;
... }
[Function: fun1]
> fun1( true, 1, 2 )
4
> fun1( true, 'aa', 3 )
Thrown: 'argument b not number'
, , , .
, +, - โฆ - - ( ), - .
let r = b
r = c
, .
Typescript:
function fun1( a:boolean, b:number, c:number ){
let r = b;
if( a ) r = c;
return r + r;
}
function fun2( a:boolean, b:number, c:string ){
let r = b;
if( a ) r = c;
return r + r;
}
> tsc ./index.ts
index.ts:9:13 - error TS2322: Type 'string' is not assignable to type 'number'.
9 if( a ) r = c;
~
Found 1 error.
, string
number
.
- , .
- , ( ) .
: f(a)=f(g(a))
TypeScript:
function f(a:number) : number {
return a+a;
}
function g(a:number) : number {
return a;
}
console.log( f(1)===f(g(1)) )
- .
- , , ..
function f(a:number) : number {
return a+a;
}
function g(a:number) : number {
return a-1;
}
let r = f(1)
r = f(g(1))
function f(a:number) : number {
return a+a;
}
function g(a:number) : string {
return (a-1) + "";
}
let r = f(1)
r = f(g(1))
( ), :
g string
f number
TypeScript.
, // - , / .
-
- -, TypeScript, - Scala, .
, Solid
- , - ,
- , . โโ
:
N
N , : {0, 1, 2, 3, โฆ }
N* : {1, 2, 3, โฆ }
Z - (+/-)
Q - ( ), Z
R - ( , e, โฆ)
C - a+bi, a,b - , i -
:
any -
number -
int -
double - ()
string -
TypeScript
function sum_of_int( a:int, b:int ) : int { return a+b; }
function sum_of_double( a:double, b:double ) : double { return a+b; }
function compare_equals( a:number, b:number ) : boolean { a==b }
let res1 : int = sum_of_int( 1, 2 )
, .. - int, int.
-
let res1 : number = sum_of_int( 1, 2 )
res1 = sum_of_double( 1.2, 2.3 )
res1 - number.
res1 = sum_of_int( 1, 2 ), res1 int, , .. int number number
res1 = sum_of_double( 1.2, 2.3 ) - res1 double ,
? , , .. res1:
let res1 : number = sum_of_int( 1, 2 )
let res2 : number = sum_of_doube( 1.2, 2.3 )
if( compare_equals(res1, res2) ){
...
}
, , , โโ
: Box Circle
class Box {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
}
class Circle {
radius : number
constructor( r: number ){
this.radius = r
}
}
, ,
let boxs : Box[] = [ new Box(1,1), new Box(2,2) ]
let circles : Circle[] = [ new Circle(1), new Circle(2) ]
2 , ,
function areaOfBox( shape:Box ):number { return shape.width * shape.height }
function areaOfCircle( shape:Circle ):number { return shape.radius * shape.radius * Math.PI }
:
boxs.map( areaOfBox ).reduce( (a,b,idx,arr)=>a+b ) +
circles.map( areaOfCircle ).reduce( (a,b,idx,arr)=>a+b )
, / (, ).
, - , , - .
/ - area():number.
interface Shape { area():number }
, Box Circle Shape, areaOfBox, areaOfCircle area.
class Box implements Shape {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
area():number {
return this.width * this.height
}
}
class Circle implements Shape {
radius : number
constructor( r: number ){
this.radius = r
}
area():number {
return this.radius * this.radius * Math.PI
}
}
,
let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2) ]
shapes.map( s => s.area() ).reduce( (a,b,idx,arr)=>a+b )
, -
Shape, (.. ) (Box, Circle).
, Box Circle Shape.
, ..
let a = b
, :
a b - ,
a , b - a - -
a b, b - () - - - .
a b - - .
, Shape
class Foo {
}
let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2), new Foo() ]
shapes.map( s => s.area() ).reduce( (a,b,idx,arr)=>a+b )
- :
> tsc index.ts
index.ts:31:84 - error TS2741: Property 'area' is missing in type 'Foo' but required in type 'Shape'.
31 let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2), new Foo() ]
~~~~~~~~~
index.ts:2:5
2 area():number
~~~~~~~~~~~~~
'area' is declared here.
Found 1 error.
Foo area, Shape.
SOLID
L - LSP - (Liskov substitution principle): ยซ ยป. . .
-
-, , , .
, Scala :
package xyz.cofe.sample.inv
object App {
// , String, Boolean, : (String)=>Boolean
def strCmp(a:String):Boolean = a.contains("1")
// , Int, Boolean, : (Int)=>Boolean
def intCmp(a:Int):Boolean = a==1
// , String, Boolean, : (Any)=>Boolean
def anyCmp(a:Any):Boolean = true
def main(args:Array[String]):Unit = {
// Boolean = Boolean
val call1 : Boolean = strCmp("a")
// - Any = Boolean
val call2 : Any = strCmp("b")
// : (String)=>Boolean = (String)=>Boolean
val cmp1 : (String)=>Boolean = App.strCmp;
// - (String)=>Boolean = (Any)=>Boolean
val cmp2 : (String)=>Boolean = App.anyCmp
// : (String)=>Boolean = (String)=>Boolean
val cmp3 : (Any)=>Boolean = App.anyCmp
// !!!!!!!!!!!!!!!!!!!!!!!
//
// - (Any)=>Boolean = (String)=>Boolean
val cmp4 : (Any)=>Boolean = App.strCmp
}
}
Scala:
Any
-
Int, Boolean, String
-Any
,
:
(_,_)=>_
= .
/= .
val
Scala,const
JS
:
// Boolean = Boolean
val call1 : Boolean = strCmp("a")
// : (String)=>Boolean = (String)=>Boolean
val cmp1 : (String)=>Boolean = App.strCmp;
cmp1 - , , :
(String)=>Boolean (String)=>Boolean
-
// - Any = Boolean
val call2 : Any = strCmp("b")
// - (String)=>Boolean = (Any)=>Boolean
val cmp2 : (String)=>Boolean = App.anyCmp
call2, , cmp2.
(String) => Boolean (Any) => Boolean
String -> -> Any - -.
, WTF? - !
// , String, Boolean, : (String)=>Boolean
def strCmp(a:String):Boolean = a.contains("1")
// , String, Boolean, : (Any)=>Boolean
def anyCmp(a:Any):Boolean = true
cmp2( "abc" )
"abc"
anyCmp(a:Any)
, String Any, .
anyCmp( "string" )
anyCmp( 1 )
, anyCmp( true )
- ,
,
()
.. , - , -.
:
-
assign a <- b
- -
call a -> b
, :
-,
-,
Scala, TypeScript
TypeScript 4.2.4 - /
interface Shape {
area():number
}
class Box implements Shape {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
area():number {
return this.width * this.height
}
}
class Circle implements Shape {
radius : number
constructor( r: number ){
this.radius = r
}
area():number {
return this.radius * this.radius * Math.PI
}
}
class Foo {
}
const f1 : (number)=> boolean = a => true;
const f2 : (object)=> boolean = a => typeof(a)=='function';
const f3 : (any)=>boolean = f1;
const f4 : (number)=>boolean = f3;
const _f1 : (Box)=>boolean = a => true
const _f2 : (any)=>boolean = _f1
const _f3 : (Shape)=>boolean = _f1
const f3 : (any)=>boolean = f1;
const _f3 : (Shape)=>boolean = _f1
( ) ,
user@user-Modern-14-A10RB:03:14:17:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc -version Version 4.2.4 user@user-Modern-14-A10RB:03:16:53:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc --strictFunctionTypes index.ts user@user-Modern-14-A10RB:03:18:26:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc --alwaysStrict index.ts user@user-Modern-14-A10RB:03:19:04:~/code/blog/itdocs/code-skill/types:
, .
-/-
.
!
, , .
- - , .
- - .
C , JS , , .
- , .
, , .
:
:
( )
( )
( )
( )
( )
( )
, .
- ( ) - .
.
Variasi adalah, pertama-tama, adanya properti / metode yang menarik untuk tugas kita. Dan ini adalah mekanisme kontrol kompiler untuk memastikan bahwa properti ini ada.
Jadi, misalnya, objek ini atau itu tidak hanya semacam di bawah kelas, tetapi juga mengimplementasikan (melalui antarmuka) properti / metode yang menarik bagi kita - inilah yang saya maksud dengan kata compatibility .
Kemudian Anda dapat berbicara tentang pewarisan berganda, sifat, dan pesona lain dari bahasa modern, tetapi ini di luar cakupan topik.