- Timestamp:
- May 15, 2019, 3:57:26 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 3648d98
- Parents:
- 9e1d485 (diff), be567e9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- doc/proposals
- Files:
-
- 1 deleted
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/vtable.md
r9e1d485 r69bafd2 1 1 Proposal For Use of Virtual Tables 2 2 ================================== 3 4 This is an adaptation of the earlier virtual proposal, updating it with new5 ideas, re-framing it and laying out more design decisions. It should6 eventually replace the earlier proposal, but not all features and syntax have7 been converted to the new design.8 3 9 4 The basic concept of a virtual table (vtable) is the same here as in most … … 93 88 } 94 89 } 90 91 With a more complete widget trait you could, for example, construct a UI tool 92 kit that can declare containers that hold widgets without knowing about the 93 widget types. Making it reasonable to extend the tool kit. 95 94 96 95 The trait types can also be used in the types of assertions on traits as well. … … 244 243 We would also like to implement hierarchical relations between types. 245 244 246 AstNode 247 |-ParseNode 248 | |-Declaration 249 | | |-DeclarationWithType 250 | | |-StructureDeclaration 251 | |-Statement 252 | | |-CompoundStatement 253 | |-Expression 254 |-Type 245 ast_node 246 |-expression_node 247 | |-operator_expression 248 | 249 |-statement_node 250 | |-goto_statement 251 | 252 |-declaration_node 253 |-using_declaration 254 |-variable_declaration 255 255 256 256 Virtual tables by themselves are not quite enough to implement this system. … … 315 315 } 316 316 317 This system does not support multiple inheritance. The system could be 318 extended to support it or a limited form (ex. you may have multiple parents 319 but they may not have a common ancestor). However this proposal focuses just 320 on using hierachy as organization. Other uses for reusable/genaric code or 321 shared interfaces is left for other features of the language. 322 317 323 ### Extension: Structural Inheritance 318 324 An extension would be allow structures to be used as internal nodes on the … … 354 360 solution but only works if we have exactly 1 vtable for each type. The second 355 361 is to put a pointer to the type id in each vtable. This has more overhead but 356 allows multiple vtables .362 allows multiple vtables per type. 357 363 358 364 struct <trait>_vtable { … … 367 373 // Trait dependent list of vtable members. 368 374 }; 375 376 One important restriction is that only one instance of each typeid in memory. 377 There is a ".gnu.linkonce" feature in the linker that might solve the issue. 369 378 370 379 ### Virtual Casts … … 423 432 io_error * error = (virtual)exc; 424 433 434 #### Sample Implementation 435 This cast implementation assumes a type id layout similar to the one given 436 above. Also this code is definitely in the underlying C. Functions that give 437 this functionality could exist in the standard library but these are meant to 438 be produced by code translation of the virtual cast. 439 440 bool is_in_subtree(typeid const * root, typeid const * id) { 441 if (root == id) { 442 return true 443 } else if (NULL == id->parent) { 444 return false; 445 } else { 446 return is_in_subtree(root, id->parent); 447 } 448 } 449 450 void * virtual_cast(typeid const * target, void * value) { 451 return is_in_subtree(target, *(typeid const **)value) ? value : NULL; 452 } 453 454 The virtual cast function might have to be wrapped with some casts to make it 455 compile without warning. 456 457 For the implicate target type we may be able to lean on the type resolution 458 system that already exists. If the casting to ancestor type is built into 459 the resolution then the impicate target could be decided by picking an 460 overload, generated for each hierarchial type (here io_error and its root 461 type exception). 462 463 io_error * virtual_cast(exception * value) { 464 return virtual_cast(io_error_typeid, value); 465 } 466 425 467 ### Extension: Inline vtables 426 468 Since the structures here are usually made to be turned into trait objects … … 436 478 to allow access to all three options. 437 479 480 The pointer to virtual table field on structures might implicately added (the 481 types have to declare they are a child here) or created with a declaration, 482 possibly like the one used to create the assertion. 483 438 484 ### Virtual Tables as Types 439 485 Here we consider encoding plus the implementation of functions on it to be a … … 442 488 and implementation. 443 489 490 ### Question: Wrapping Structures 491 One issue is what to do with concrete types at the base of the type tree. 492 When we are working with the concrete type generally it would like them to be 493 regular structures with direct calls. On the other hand for interactions with 494 other types in the hierarchy it is more convenent for the type already to be 495 cast. 496 497 Which of these two should we use? Should we support both and if so how do we 498 choose which one is being used at any given time. 499 500 On a related note I have been using pointers two trait types here, as that 501 is how many existing languages handle it. However the generic objects might 502 be only one or two pointers wide passing the objects as a whole would not 503 be very expensive and all operations on the generic objects probably have 504 to be defined anyways. 505 444 506 Resolution Scope 445 507 ---------------- … … 534 596 Stack allocated functions interact badly with this because they are not 535 597 static. There are several ways to try to resolve this, however without a 536 general solution most can only buy time. 598 general solution most can keep vtables from making the existing thunk problem 599 worse, they don't do anything to solve it. 537 600 538 601 Filling in some fields of a static vtable could cause issues on a recursive … … 549 612 shortest lifetime of a function assigned to it. However this still limits the 550 613 lifetime "implicitly" and returns to the original problem with thunks. 614 615 Odds And Ends 616 ------------- 617 618 In addition to the main design there are a few extras that should be 619 considered. They are not part of the core design but make the new uses fully 620 featured. 621 622 ### Extension: Parent-Child Assertion 623 For hierarchy types in regular traits, generic functions or generic structures 624 we may want to be able to check parent-child relationships between two types 625 given. For this we might have to add another primitive assertion. It would 626 have the following form if declared in code: 627 628 trait is_parent_child(dtype Parent, dtype Child) { <built-in magic> } 629 630 This assertion is satified if Parent is an ancestor of Child in a hierarchy. 631 In other words Child can be statically cast to Parent. The cast from Parent 632 to child would be dynamically checked as usual. 633 634 However in this form there are two concerns. The first that Parent will 635 usually be consistent for a given use, it will not be a variable. Second is 636 that we may also need the assertion functions. To do any casting/conversions 637 anyways. 638 TODO: Talk about when we wrap a concrete type and how that leads to "may". 639 640 To this end it may be better that the parent trait combines the usual 641 assertions plus this new primitive assertion. There may or may not be use 642 cases for accessing just one half and providing easy access to them may be 643 required depending on how that turns out. 644 645 trait Parent(dtype T | interface(T)) virtual(<grand-parent?>) { } 646 647 ### Extension: sizeof Compatablity 648 Trait types are always sized, it may even be a fixed size like how pointers 649 have the same size regardless of what they point at. However their contents 650 may or may not be of a known size (if the `sized(...)` assertion is used). 651 652 Currently there is no way to access this information. If it is needed a 653 special syntax would have to be added. Here a special case of `sizeof` is 654 used. 655 656 struct line aLine; 657 trait drawable widget = aLine; 658 659 size_t x = sizeof(widget); 660 size_t y = sizeof(trait drawable); 661 662 As usual `y`, size of the type, is the size of the local storage used to put 663 the value into. The other case `x` checks the saved stored value in the 664 virtual table and returns that.
Note: See TracChangeset
for help on using the changeset viewer.