vim9class.txt 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. *vim9class.txt* For Vim version 9.0. Last change: 2022 Dec 11
  2. VIM REFERENCE MANUAL by Bram Moolenaar
  3. NOTE - This is under development, anything can still change! - NOTE
  4. Vim9 classes, objects, interfaces, types and enums.
  5. 1. Overview |Vim9-class-overview|
  6. 2. A simple class |Vim9-simple-class|
  7. 3. Using an abstract class |Vim9-abstract-class|
  8. 4. Using an interface |Vim9-using-interface|
  9. 5. More class details |Vim9-class|
  10. 6. Type definition |Vim9-type|
  11. 7. Enum |Vim9-enum|
  12. 9. Rationale
  13. 10. To be done later
  14. ==============================================================================
  15. 1. Overview *Vim9-class-overview*
  16. The fancy term is "object-oriented programming". You can find lots of study
  17. material about this subject. Here we document what |Vim9| script provides,
  18. assuming you know the basics already. Added are helpful hints about how
  19. to use this functionality effectively.
  20. The basic item is an object:
  21. - An object stores state. It contains one or more variables that can each
  22. have a value.
  23. - An object usually provides functions that manipulate its state. These
  24. functions are invoked "on the object", which is what sets it apart from the
  25. traditional separation of data and code that manipulates the data.
  26. - An object has a well defined interface, with typed member variables and
  27. member functions.
  28. - Objects are created by a class and all objects have the same interface.
  29. This never changes, it is not dynamic.
  30. An object can only be created by a class. A class provides:
  31. - A new() method, the constructor, which returns an object for the class.
  32. This method is invoked on the class name: MyClass.new().
  33. - State shared by all objects of the class: class variables and constants.
  34. - A hierarchy of classes, with super-classes and sub-classes, inheritance.
  35. An interface is used to specify properties of an object:
  36. - An object can declare several interfaces that it implements.
  37. - Different objects implementing the same interface can be used the same way.
  38. The class hierarchy allows for single inheritance. Otherwise interfaces are
  39. to be used where needed.
  40. Class modeling ~
  41. You can model classes any way you like. Keep in mind what you are building,
  42. don't try to model the real world. This can be confusing, especially because
  43. teachers use real-world objects to explain class relations and you might think
  44. your model should therefore reflect the real world. It doesn't! The model
  45. should match your purpose.
  46. You will soon find that composition is often better than inheritance. Don't
  47. waste time trying to find the optimal class model. Or waste time discussing
  48. whether a square is a rectangle or that a rectangle is a square. It doesn't
  49. matter.
  50. ==============================================================================
  51. 2. A simple class *Vim9-simple-class*
  52. Let's start with a simple example: a class that stores a text position: >
  53. class TextPosition
  54. this.lnum: number
  55. this.col: number
  56. def new(lnum: number, col: number)
  57. this.lnum = lnum
  58. this.col = col
  59. enddef
  60. def SetLnum(lnum: number)
  61. this.lnum = lnum
  62. enddef
  63. def SetCol(col: number)
  64. this.col = col
  65. enddef
  66. def SetPosition(lnum: number, col: number)
  67. this.lnum = lnum
  68. this.col = col
  69. enddef
  70. endclass
  71. < *object* *Object*
  72. You can create an object from this class with the new() method: >
  73. var pos = TextPosition.new(1, 1)
  74. The object members "lnum" and "col" can be accessed directly: >
  75. echo $'The text position is ({pos.lnum}, {pos.col})'
  76. < *E1317* *E1327*
  77. If you have been using other object-oriented languages you will notice that
  78. in Vim the object members are consistently referred to with the "this."
  79. prefix. This is different from languages like Java and TypeScript. This
  80. naming convention makes the object members easy to spot. Also, when a
  81. variable does not have the "this." prefix you know it is not an object member.
  82. Member write access ~
  83. Now try to change an object member directly: >
  84. pos.lnum = 9
  85. This will give you an error! That is because by default object members can be
  86. read but not set. That's why the class provides a method for it: >
  87. pos.SetLnum(9)
  88. Allowing to read but not set an object member is the most common and safest
  89. way. Most often there is no problem using a value, while setting a value may
  90. have side effects that need to be taken care of. In this case, the SetLnum()
  91. method could check if the line number is valid and either give an error or use
  92. the closest valid value.
  93. If you don't care about side effects and want to allow the object member to be
  94. changed at any time, you can make it public: >
  95. public this.lnum: number
  96. public this.col number
  97. Now you don't need the SetLnum(), SetCol() and SetPosition() methods, setting
  98. "pos.lnum" directly above will no longer give an error.
  99. Private members ~
  100. On the other hand, if you do not want the object members to be read directly,
  101. you can make them private. This is done by prefixing an underscore to the
  102. name: >
  103. this._lnum: number
  104. this._col number
  105. Now you need to provide methods to get the value of the private members.
  106. These are commonly call getters. We recommend using a name that starts with
  107. "Get": >
  108. def GetLnum(): number
  109. return this._lnum
  110. enddef
  111. def GetCol() number
  112. return this._col
  113. enddef
  114. This example isn't very useful, the members might as well have been public.
  115. It does become useful if you check the value. For example, restrict the line
  116. number to the total number of lines: >
  117. def GetLnum(): number
  118. if this._lnum > this._lineCount
  119. return this._lineCount
  120. endif
  121. return this._lnum
  122. enddef
  123. Simplifying the new() method ~
  124. Many constructors take values for the object members. Thus you very often see
  125. this pattern: >
  126. this.lnum: number
  127. this.col: number
  128. def new(lnum: number, col: number)
  129. this.lnum = lnum
  130. this.col = col
  131. enddef
  132. Not only is this text you need to write, it also has the type of each member
  133. twice. Since this is so common a shorter way to write new() is provided: >
  134. def new(this.lnum, this.col)
  135. enddef
  136. The semantics are easy to understand: Providing the object member name,
  137. including "this.", as the argument to new() means the value provided in the
  138. new() call is assigned to that object member. This mechanism is coming from
  139. the Dart language.
  140. The sequence of constructing a new object is:
  141. 1. Memory is allocated and cleared. All values are zero/false/empty.
  142. 2. For each declared member that has an initializer, the expression is
  143. evaluated and assigned to the member. This happens in the sequence the
  144. members are declared in the class.
  145. 3. Arguments in the new() method in the "this.name" form are assigned.
  146. 4. The body of the new() method is executed.
  147. TODO: for a sub-class the constructor of the parent class will be invoked
  148. somewhere.
  149. ==============================================================================
  150. 3. Using an abstract class *Vim9-abstract-class*
  151. An abstract class forms the base for at least one sub-class. In the class
  152. model one often finds that a few classes have the same properties that can be
  153. shared, but a class with those properties does not have enough state to create
  154. an object from. A sub-class must extend the abstract class and add the
  155. missing state and/or methods before it can be used to create objects for.
  156. An abstract class does not have a new() method.
  157. For example, a Shape class could store a color and thickness. You cannot
  158. create a Shape object, it is missing the information about what kind of shape
  159. it is. The Shape class functions as the base for a Square and a Triangle
  160. class, for which objects can be created. Example: >
  161. abstract class Shape
  162. this.color = Color.Black
  163. this.thickness = 10
  164. endclass
  165. class Square extends Shape
  166. this.size: number
  167. def new(this.size)
  168. enddef
  169. endclass
  170. class Triangle extends Shape
  171. this.base: number
  172. this.height: number
  173. def new(this.base, this.height)
  174. enddef
  175. endclass
  176. <
  177. *class-member* *:static*
  178. Class members are declared with "static". They are used by the name without a
  179. prefix: >
  180. class OtherThing
  181. this.size: number
  182. static totalSize: number
  183. def new(this.size)
  184. totalSize += this.size
  185. enddef
  186. endclass
  187. <
  188. *class-method*
  189. Class methods are also declared with "static". They have no access to object
  190. members, they cannot use the "this" keyword. >
  191. class OtherThing
  192. this.size: number
  193. static totalSize: number
  194. " Clear the total size and return the value it had before.
  195. static def ClearTotalSize(): number
  196. var prev = totalSize
  197. totalSize = 0
  198. return prev
  199. enddef
  200. endclass
  201. ==============================================================================
  202. 4. Using an interface *Vim9-using-interface*
  203. The example above with Shape, Square and Triangle can be made more useful if
  204. we add a method to compute the surface of the object. For that we create the
  205. interface called HasSurface, which specifies one method Surface() that returns
  206. a number. This example extends the one above: >
  207. abstract class Shape
  208. this.color = Color.Black
  209. this.thickness = 10
  210. endclass
  211. interface HasSurface
  212. def Surface(): number
  213. endinterface
  214. class Square extends Shape implements HasSurface
  215. this.size: number
  216. def new(this.size)
  217. enddef
  218. def Surface(): number
  219. return this.size * this.size
  220. enddef
  221. endclass
  222. class Triangle extends Shape implements HasSurface
  223. this.base: number
  224. this.height: number
  225. def new(this.base, this.height)
  226. enddef
  227. def Surface(): number
  228. return this.base * this.height / 2
  229. enddef
  230. endclass
  231. The interface name can be used as a type: >
  232. var shapes: list<HasSurface> = [
  233. Square.new(12),
  234. Triangle.new(8, 15),
  235. ]
  236. for shape in shapes
  237. echo $'the surface is {shape.Surface()}'
  238. endfor
  239. ==============================================================================
  240. 5. More class details *Vim9-class* *Class* *class*
  241. Defining a class ~
  242. *:class* *:endclass* *:abstract*
  243. A class is defined between `:class` and `:endclass`. The whole class is
  244. defined in one script file. It is not possible to add to a class later.
  245. A class can only be defined in a |Vim9| script file. *E1316*
  246. A class cannot be defined inside a function.
  247. It is possible to define more than one class in a script file. Although it
  248. usually is better to export only one main class. It can be useful to define
  249. types, enums and helper classes though.
  250. The `:abstract` keyword may be prefixed and `:export` may be used. That gives
  251. these variants: >
  252. class ClassName
  253. endclass
  254. export class ClassName
  255. endclass
  256. abstract class ClassName
  257. endclass
  258. export abstract class ClassName
  259. endclass
  260. <
  261. *E1314*
  262. The class name should be CamelCased. It must start with an uppercase letter.
  263. That avoids clashing with builtin types.
  264. *E1315*
  265. After the class name these optional items can be used. Each can appear only
  266. once. They can appear in any order, although this order is recommended: >
  267. extends ClassName
  268. implements InterfaceName, OtherInterface
  269. specifies SomeInterface
  270. < *extends*
  271. A class can extend one other class.
  272. *implements*
  273. A class can implement one or more interfaces.
  274. *specifies*
  275. A class can declare its interface, the object members and methods, with a
  276. named interface. This avoids the need for separately specifying the
  277. interface, which is often done in many languages, especially Java.
  278. Items in a class ~
  279. *E1318* *E1325* *E1326*
  280. Inside a class, in betweeen `:class` and `:endclass`, these items can appear:
  281. - An object member declaration: >
  282. this._memberName: memberType
  283. this.memberName: memberType
  284. public this.memberName: memberType
  285. - A constructor method: >
  286. def new(arguments)
  287. def newName(arguments)
  288. - An object method: >
  289. def SomeMethod(arguments)
  290. Defining an interface ~
  291. *:interface* *:endinterface*
  292. An interface is defined between `:interface` and `:endinterface`. It may be
  293. prefixed with `:export`: >
  294. interface InterfaceName
  295. endinterface
  296. export interface InterfaceName
  297. endinterface
  298. An interface can declare object members, just like in a class but without any
  299. initializer.
  300. An interface can declare methods with `:def`, including the arguments and
  301. return type, but without the body and without `:enddef`. Example: >
  302. interface HasSurface
  303. this.size: number
  304. def Surface(): number
  305. endinterface
  306. The "Has" prefix can be used to make it easier to guess this is an interface
  307. name, with a hint about what it provides.
  308. Default constructor ~
  309. In case you define a class without a new() method, one will be automatically
  310. defined. This default constructor will have arguments for all the object
  311. members, in the order they were specified. Thus if your class looks like: >
  312. class AutoNew
  313. this.name: string
  314. this.age: number
  315. this.gender: Gender
  316. endclass
  317. Then The default constructor will be: >
  318. def new(this.name = v:none, this.age = v:none, this.gender = v:none)
  319. enddef
  320. All object members will be used, also private access ones.
  321. The "= v:none" default values make the arguments optional. Thus you can also
  322. call `new()` without any arguments. No assignment will happen and the default
  323. value for the object members will be used. This is a more useful example,
  324. with default values: >
  325. class TextPosition
  326. this.lnum: number = 1
  327. this.col: number = 1
  328. endclass
  329. If you want the constructor to have mandatory arguments, you need to write it
  330. yourself. For example, if for the AutoNew class above you insist on getting
  331. the name, you can define the constructor like this: >
  332. def new(this.name, this.age = v:none, this.gender = v:none)
  333. enddef
  334. < *E1328*
  335. Note that you cannot use another default value than "v:none" here. If you
  336. want to initialize the object members, do it where they are declared. This
  337. way you only need to look in one place for the default values.
  338. Multiple constructors ~
  339. Normally a class has just one new() constructor. In case you find that the
  340. constructor is often called with the same arguments you may want to simplify
  341. your code by putting those arguments into a second constructor method. For
  342. example, if you tend to use the color black a lot: >
  343. def new(this.garment, this.color, this.size)
  344. enddef
  345. ...
  346. var pants = new(Garment.pants, Color.black, "XL")
  347. var shirt = new(Garment.shirt, Color.black, "XL")
  348. var shoes = new(Garment.shoes, Color.black, "45")
  349. Instead of repeating the color every time you can add a constructor that
  350. includes it: >
  351. def newBlack(this.garment, this.size)
  352. this.color = Color.black
  353. enddef
  354. ...
  355. var pants = newBlack(Garment.pants, "XL")
  356. var shirt = newBlack(Garment.shirt, "XL")
  357. var shoes = newBlack(Garment.shoes, "9.5")
  358. Note that the method name must start with "new". If there is no method called
  359. "new()" then the default constructor is added, even though there are other
  360. constructor methods.
  361. ==============================================================================
  362. 6. Type definition *Vim9-type* *:type*
  363. A type definition is giving a name to a type specification. For Example: >
  364. :type ListOfStrings list<string>
  365. TODO: more explanation
  366. ==============================================================================
  367. 7. Enum *Vim9-enum* *:enum* *:endenum*
  368. An enum is a type that can have one of a list of values. Example: >
  369. :enum Color
  370. White
  371. Red
  372. Green
  373. Blue
  374. Black
  375. :endenum
  376. TODO: more explanation
  377. ==============================================================================
  378. 9. Rationale
  379. Most of the choices for |Vim9| classes come from popular and recently
  380. developed languages, such as Java, TypeScript and Dart. The syntax has been
  381. made to fit with the way Vim script works, such as using `endclass` instead of
  382. using curly braces around the whole class.
  383. Some common constructs of object-oriented languages were chosen very long ago
  384. when this kind of programming was still new, and later found to be
  385. sub-optimal. By this time those constructs were widely used and changing them
  386. was not an option. In Vim we do have the freedom to make different choices,
  387. since classes are completely new. We can make the syntax simpler and more
  388. consistent than what "old" languages use. Without diverting too much, it
  389. should still mostly look like what you know from existing languages.
  390. Some recently developed languages add all kinds of fancy features that we
  391. don't need for Vim. But some have nice ideas that we do want to use.
  392. Thus we end up with a base of what is common in popular languages, dropping
  393. what looks like a bad idea, and adding some nice features that are easy to
  394. understand.
  395. The main rules we use to make decisions:
  396. - Keep it simple.
  397. - No surprises, mostly do what other languages are doing.
  398. - Avoid mistakes from the past.
  399. - Avoid the need for the script writer to consult the help to understand how
  400. things work, most things should be obvious.
  401. - Keep it consistent.
  402. - Aim at an average size plugin, not at a huge project.
  403. Using new() for the constructor ~
  404. Many languages use the class name for the constructor method. A disadvantage
  405. is that quite often this is a long name. And when changing the class name all
  406. constructor methods need to be renamed. Not a big deal, but still a
  407. disadvantage.
  408. Other languages, such as TypeScript, use a specific name, such as
  409. "constructor()". That seems better. However, using "new" or "new()" to
  410. create a new object has no obvious relation with "constructor()".
  411. For |Vim9| script using the same method name for all constructors seemed like
  412. the right choice, and by calling it new() the relation between the caller and
  413. the method being called is obvious.
  414. No overloading of the constructor ~
  415. In Vim script, both legacy and |Vim9| script, there is no overloading of
  416. functions. That means it is not possible to use the same function name with
  417. different types of arguments. Therefore there also is only one new()
  418. constructor.
  419. With |Vim9| script it would be possible to support overloading, since
  420. arguments are typed. However, this gets complicated very quickly. Looking at
  421. a new() call one has to inspect the types of the arguments to know which of
  422. several new() methods is actually being called. And that can require
  423. inspecting quite a bit of code. For example, if one of the arguments is the
  424. return value of a method, you need to find that method to see what type it is
  425. returning.
  426. Instead, every constructor has to have a different name, starting with "new".
  427. That way multiple constructors with different arguments are possible, while it
  428. is very easy to see which constructor is being used. And the type of
  429. arguments can be properly checked.
  430. No overloading of methods ~
  431. Same reasoning as for the constructor: It is often not obvious what type
  432. arguments have, which would make it difficult to figure out what method is
  433. actually being called. Better just give the methods a different name, then
  434. type checking will make sure it works as you intended. This rules out
  435. polymorphism, which we don't really need anyway.
  436. Using "this.member" everywhere ~
  437. The object members in various programming languages can often be accessed in
  438. different ways, depending on the location. Sometimes "this." has to be
  439. prepended to avoid ambiguity. They are usually declared without "this.".
  440. That is quite inconsistent and sometimes confusing.
  441. A very common issue is that in the constructor the arguments use the same name
  442. as the object member. Then for these members "this." needs to be prefixed in
  443. the body, while for other members this is not needed and often omitted. This
  444. leads to a mix of members with and without "this.", which is inconsistent.
  445. For |Vim9| classes the "this." prefix is always used. Also for declaring the
  446. members. Simple and consistent. When looking at the code inside a class it's
  447. also directly clear which variable references are object members and which
  448. aren't.
  449. Single inheritance and interfaces ~
  450. Some languages support multiple inheritance. Although that can be useful in
  451. some cases, it makes the rules of how a class works quite complicated.
  452. Instead, using interfaces to declare what is supported is much simpler. The
  453. very popular Java language does it this way, and it should be good enough for
  454. Vim. The "keep it simple" rule applies here.
  455. Explicitly declaring that a class supports an interface makes it easy to see
  456. what a class is intended for. It also makes it possible to do proper type
  457. checking. When an interface is changed any class that declares to implement
  458. it will be checked if that change was also changed. The mechanism to assume a
  459. class implements an interface just because the methods happen to match is
  460. brittle and leads to obscure problems, let's not do that.
  461. Using class members ~
  462. Using "static member" to declare a class member is very common, nothing new
  463. here. In |Vim9| script these can be accessed directly by their name. Very
  464. much like how a script-local variable can be used in a function. Since object
  465. members are always accessed with "this." prepended, it's also quickly clear
  466. what kind of member it is.
  467. TypeScript prepends the class name before the class member, also inside the
  468. class. This has two problems: The class name can be rather long, taking up
  469. quite a bit of space, and when the class is renamed all these places need to
  470. be changed too.
  471. Using "ClassName.new()" to construct an object ~
  472. Many languages use the "new" operator to create an object, which is actually
  473. kind of strange, since the constructor is defined as a method with arguments,
  474. not a command. TypeScript also has the "new" keyword, but the method is
  475. called "constructor()", it is hard to see the relation between the two.
  476. In |Vim9| script the constructor method is called new(), and it is invoked as
  477. new(), simple and straightforward. Other languages use "new ClassName()",
  478. while there is no ClassName() method, it's a method by another name in the
  479. class called ClassName. Quite confusing.
  480. Default read access to object members ~
  481. Some users will remark that the access rules for object members are
  482. asymmetric. Well, that is intentional. Changing a value is a very different
  483. action than reading a value. The read operation has no side effects, it can
  484. be done any number of times without affecting the object. Changing the value
  485. can have many side effects, and even have a ripple effect, affecting other
  486. objects.
  487. When adding object members one usually doesn't think much about this, just get
  488. the type right. And normally the values are set in the new() method.
  489. Therefore defaulting to read access only "just works" in most cases. And when
  490. directly writing you get an error, which makes you wonder if you actually want
  491. to allow that. This helps writing code with fewer mistakes.
  492. Making object members private with an underscore ~
  493. When an object member is private, it can only be read and changed inside the
  494. class (and in sub-classes), then it cannot be used outside of the class.
  495. Prepending an underscore is a simple way to make that visible. Various
  496. programming languages have this as a recommendation.
  497. In case you change your mind and want to make the object member accessible
  498. outside of the class, you will have to remove the underscore everywhere.
  499. Since the name only appears in the class (and sub-classes) they will be easy
  500. to find and change.
  501. The other way around is much harder: you can easily prepend an underscore to
  502. the object member inside the class to make it private, but any usage elsewhere
  503. you will have to track down and change. You may have to make it a "set"
  504. method call. This reflects the real world problem that taking away access
  505. requires work to be done for all places where that access exists.
  506. An alternative would have been using the "private" keyword, just like "public"
  507. changes the access in the other direction. Well, that's just to reduce the
  508. number of keywords.
  509. No protected object members ~
  510. Some languages provide several ways to control access to object members. The
  511. most known is "protected", and the meaning varies from language to language.
  512. Others are "shared", "private" and even "friend".
  513. These rules make life more difficult. That can be justified in projects where
  514. many people work on the same, complex code where it is easy to make mistakes.
  515. Especially when refactoring or other changes to the class model.
  516. The Vim scripts are expected to be used in a plugin, with just one person or a
  517. small team working on it. Complex rules then only make it more complicated,
  518. the extra safety provide by the rules isn't really needed. Let's just keep it
  519. simple and not specify access details.
  520. ==============================================================================
  521. 10. To be done later
  522. Can a newSomething() constructor invoke another constructor? If yes, what are
  523. the restrictions?
  524. Thoughts:
  525. - Generics for a class: `class <Tkey, Tentry>`
  526. - Generics for a function: `def <Tkey> GetLast(key: Tkey)`
  527. - Mixins: not sure if that is useful, leave out for simplicity.
  528. Some things that look like good additions:
  529. - For testing: Mock mechanism
  530. An important class to be provided is "Promise". Since Vim is single
  531. threaded, connecting asynchronous operations is a natural way of allowing
  532. plugins to do their work without blocking the user. It's a uniform way to
  533. invoke callbacks and handle timeouts and errors.
  534. vim:tw=78:ts=8:noet:ft=help:norl: