📄 rationale.txt
字号:
This file tries to establish rationale of the decision basis of the libraryinterface. This file is published partly for correction.Changes of library interface resulting from contents herein may lead to dramatical impact on application source using this library (the library isworth the use anyway) Note: Phrases in quite several places may be indifferent to the author. And, information in this file may have outdated. (develop on demand, learn on demand, as programmers usually do)+------------------------------------------+| Function Reply (previously Error Report) |+------------------------------------------+ Considering codes being reused as a function (with respect to as macro), the exit points (indicating different condition, instead of the intended information) of that function are traditionally simplified to one by encoding it into a replied object (C++ adds a throwing channel for the function to exit) Caller function is thus inborn with the decoding task recovering the exit point information. There are two choices considered. Drawback of each (way of reply): a) by return (with respect to by throw) 1. Idling the dedicated throwing channel. 2. Replies are implicitly non-exaustive. Undocumented or future added report is more easier to be ignored. Lack ability to 'catch' returned reply by static type (not yet clear the use, but for the comparsion with the throw channel). 3. Not appropriate for constructor and operator members, and a bit redundant in programming. b) by throw 1. No reliable mechanism for the replied(error) semantics from diverge. From the throw mechanism definition, any throws will reappear to the caller as if the call point is replaced by the throw there, if no handler catches it, the process (stack unwinding) continues. Thus, a function call such as f() can be explicitly (in effect) replaced by the keyword throw of any of the underlying function which had thrown. (the throw point is decoded, and reappears as if the call point is the throw point). So the context, or semantics of the throw point propagated to the catch handler is basically unknown. Take for instance, a function call f() can initiate various sort of throws, invalid_argument, domain_error, overflow_error, etc... Except the context is irrelevant, to resolve the throw for a succeeful function, the handler can retry at least someway relying on the convention that function either succeeds or fails with 'trival effect' (note that semantics of the caught object now becomes a surplus in this resolution at this point). Such tries in the responsible caller is, for most failure replies, harder to report a faithful success at the end without changing or modifying the functionality... So the result would normally still be a throw someway, only more vague or more of a general failure nature. This condition recurres. Information from the net throw channel mechanism makes the semantics vague, more so the deeper of the call chain. Hence the divergent characteristic is concluded: function gets less and less functional more quickly. 2. In the stack unwinding, another throw can occur, particularily it is initiated from an asyncronous event, which will lead to terminate. 3. A function that reply by throw can not simulate that reply by return. For this library, if there are ever needs to return the value of an underlying C-function, a class passing errno information seems inevitable, hence is the class to throw(not by type). Choices seems few with this basic. This library inclines to report function reply via the return channel if not too bad (source checking utility could probably help spot the ignorance) If both the throw and return versions were to be in this library, the return verion is prefered in priority, since they are still required in the catch handler. Memory exaustion is considered inevitable (beside the hidden stack), hence constructors will throw Reply(Wym_ENOMEM) if memory allocation is/would be involved (constructors is recommended to avoid failure). Class Reply is a wrapper of the return class WyRet (same size as the return class), is intended the means to identify the throw point of the function being called, so as to mimic semantics that would be derived from the return channel. The Reply mechanism (to catch and identify the throw point before too much uncertainty gets involved in the stack unwinding) requires programming support. If application is not sure the mechanism is maintained, the other option is reserved, i.e. catch WyRet, cleanup local changes and rethrow as usual and do not interpret throw point of Reply. Throw specification documented in this library is primarily to make nothrow functions possible(destructors, cleanup codes and catch handlers want this). Throw specification is shown in documents as if it were so declared, unless compiled with WYLIB_CONFIG_THROWSPC defined, the real implement is empty. The reasons are: 1. Changes of this library is easier. Application programs seem not using throw specification often at the time. By being compiler configurable, users have option. 2. Comparing with a function that tries to simulate the specification effects, more drawbacks than documention benefits are found. .Function typedef/signature problem restricts popular use .The recurrence of runtime overhead are hardly felt worthy in functions that just return a single data item or are simple wrappers of a function or functions known nothrow. .Functions with throw spcification do not therefore encourage caller functions also to use throw specification. For caller functions are nonetheless easier to have throwing guarantee from the underlying codes that may initiate the stack unwind by whatever reason. Note: Development of this library is tending minimizing the use of throw specification if a C-library function is used. Note: Members of classs defined in wyret.h are guananteed nothrow without real throw specification. Comment: Application might feel checking the result of every function is tedious, but experience is that programming task about 2000 lines would have begun exhibiting benefits of both speed and quality, even it is expected to live only for several executions (especially with the support of source location information). A point is that widely reusable codes have to handle those 'branches', no absolute answer to the how part. Decoding of the exit point normally means to branch to a more expansive implement for a successful function request. Source location information SLI can be viewed as the branch point information for human to decode. Use of SLI reduces significant development and maintenance efforts. This is the author's experience, however. Compiler symbol WYLIB_CONFIG_NORSLI is provided to disable SLI support. Few reasons so far found of doing this but for that users (I am one) always like to use things exactly needed, zero overhead, no imposed burdon, requirements... Another reason is that the provision is handy.+-----------------------------------------------------+| General interface about object/information coupling |+-----------------------------------------------------+ For efficiency, information input/output in many cases may be attributed as 'incomplete' by using reference/pointer if address is not really meant (with respect to i/o by value), in that information does not really pass to the destination but an address. This library uses reference in place of value in the way as commonly practiced (which is also normally better) Implicication may be tricky, e.g. the self-operate-self pattern, as frequently observed in t.reset(t), is usually handled in silence as if it were passed by value. But it may be said that one more piece of information (the easier abused one) is implicitly introduced to the function domain. In some instances, the constness guarantee of the argument may not be true, the basic is when two objects overlap (exactly the ability of pointer/reference, and several of them may be in forms not immediately recognizable).+-------+| WyStr |+-------+ The primary feature of WyStr is to provide flexible char buffer and to handle the implying trailing char(0) of a C style string. WyStr is not the direct part of the conversion for the underlying syscalls and C-library, the benefits in practice is the facilitate of ::mkstemp(..), ::ttyname_r(..),..,data I/O etc. reducing the need to use C-library things such as macro PATH_MAX,..sysconf.+------------+| Compromise |+------------+ As decision is often implicit result of compromise or even random choice from the distribution pattern of practical usage. This paragraph tries to establish validation of such stuff, by simply listing known facts or phenomena that are generally applicable. 1. Derived from traditional logic (or intuition). Object A, A and none-A exist at the same moment (coexist) 2. Derived from computer mathmatics. Let t:N->N be a 1-1 transformation function, N is the set of natual number. u,v is subset of N and v=t(u). # denotes the sizeof function, then #(u)+#(!u) == #(v)+#(!v) This roughly means if set X is 'compressed' to another set, say X'. then #(!X') 'increases' by the same quantity over #(!X), vice versa. (some form of fixed-sum, infinite+finite may be questionable, though) [Hint or application] X might even be abstract notion like an C++ object can be, as experiment for instance: (order/chaos, as X is more in order, the opposite !X might be measured) (force/counter force, feature, property gain/loss in a closed system) (wake/sleep, efficient use evolution) .....+----------------------------------------------------------+| Sequence of acquisition incident: Object life cycle view |+----------------------------------------------------------+ 1. Name binding (there might be anonymous object) 2. Size binding Information to allocate memory 3. Address binding Object in this stage is called in random state. 4. Semantics binding Object is in responsible state of the occupied space. (external resource may be associated in the semantics) 5. Reversal is the object destruct process Note: Class of objects whose destructor can be runtime ignored is referred to as discardable in this library. Often, such class has no user defined destructor.----Result of the life cycle view is the basic rule of class members Constructor(..): Constructor forms are in basic the Cartesian product view of problem domain in tupple. Constructor brings an object in random state to responsible state. Reset(..) members: Reset in theroy brings an object from responsible state back to random state and then does whatever the argument corresponding constructor does. Construct/destruct/reset are implemented as composite operations of object initialization process of the life cycle view (and the symmetrical reverse). Reset() is special: [12.4.14] Once a destructor is invoked for an object, the object no longer exists; ... Because destructor can only be called legally once and the object is then regarded non-existant by the language, class design should allow state transition path that an object can always be successfully brought back to random state (may be destruct by discard). It is convenient letting reset() the bring-back function which always succeeds, or the front part of that bring-back sequence.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -