Replies: 2 comments 5 replies
-
The case against1. The "distinction" between basic and container widgetsFirstly, it is important not to make too many decisions based on the choices of other frameworks, as we take a very different (and better) approach to many things. I strongly believe that it makes sense to make decisions based on whether they are good, not whether someone else also made them. Regardless, existing precedent can still be valuable in making some decisions. However, the existing paradigms that you attempt to construe as stable precedent for this separation are simply not a good basis for such a decision. As you may have noticed, the Qt page that you link to describes menus and tabs as a "basic" widgets, so should our menus and tabs therefore use parts? You are conflating an arbitrary classification of the complexity of widgets with a coherent, categorical, and semantic separation. Basing a programmatic distinction on a purely stylistic documentation choice of a framework written in C++ that quite frequently serves as an example of what not to do is clearly a logically flawed decision. Regarding Material Design, you once again conveniently cherry-picked information to create a deliberately false impression. As you would have noticed had you accurately represented the content of the aforementioned page, Material Design classifies its components into one of six groups, which are again exclusively for stylistic documentation purposes. These groups are not just "actions" and "containment" as you claimed, but rather "actions," "communication," "containment," "navigation," "selection," and "text inputs." Moreover, had you been focused on successfully interpreting the information located on the page instead of hastily construing it to fit your argument, you would have noticed that those groups bear absolutely no resemblance to your arbitrary parts distinction. In "actions," there are both widgets that we have with parts (common buttons, etc) and ones that we have without parts (segmented buttons). In "selection," the same is true: there are widgets that we have with parts (switch) and widgets that we have without parts (date pickers). Clearly, Material Design is not making this categorization based on a "terminal widget" vs "container widget" decision; they are making it based on a semantic, functional, and purpose-based classification: what task certain groups of widgets accomplish. This is completely orthogonal to your proposal, and thus Material Design, as with Qt, gives no evidence in support of your claim. Regarding your type system analogy: I absolutely agree that it makes sense to have different types for different things; that is why we are using a type-safe language and have different types for different widgets: a 2. Capturing the "distinction" in the softwareDespite referring to "basic widgets" and "basic elements" no fewer than eleven times, you do not seem to have provided a cogent definition of them. Your only attempt at a definition made reference to being "primarily concerned with supporting a single basic function," a definition which does not seem to be consistent with your prior assertions. I would argue that a segmented button is primarily concerned with supporting a single basic function, selecting an item. Moreover, I would argue that a date view is primarily concerned with supporting a single basic function, selecting a date. Why don't those widgets use parts, as so-called "basic widgets"? Your vague, arbitrary, and weak definition of a "basic widget" leaves significant room for interpretation, which only leads to more arguments and inconsistency. Furthermore, you claim that the use of parts on "basic widgets" makes it clear that they are "fully managed by the main widget," but don't many widgets without parts fully mange their children, like switches, date view, and slice view? Once again, you are creating a pointless and inaccurate distinction that does nothing but create further confusion. Additionally, I think it is clear that text and icons are "basic widgets" under any reasonable definition, so shouldn't a button that contains text and icons therefore be a composite widget, which you defined as "obviously containers of basic elements"? The only true categorical distinction that you can make is between true terminal widgets like text and icons that have literally no children or parts, and composite widgets that contain any children or parts of any kind, such as buttons, frames, and date views. However, this distinction is already quite clearly made: any widget that embeds Layout in any way, including through parts, is quite clearly a composite widget, and anything that doesn't is not. There is no point in creating further unnecessary and vague distinctions, and I highly doubt that anyone will complain that our framework does not sufficiently "reflect the natural ontology of the space of things it implements." 3. ConsistencyDespite your noble attempt to "establish a clear, consistent sent [sic] of principles" for the use of parts, your definition inevitably falls back on unoriginal tautologies: parts go in parts and children go in children (shocking!). Arguing that "basic widgets" should use parts because parts go in "basic widgets" hardly constitutes a meaningful, clear, and consistent set of principles. Instead, you are committing two logical fallacies: circular reasoning and sunk cost fallacy. You are basing your argument entirely on circular tautologies and the assertion that we must use something more because we already have to use it some. If we have to use some Objective-C for the macOS driver, why don't we just use it for math32? They both seem like "basic libraries" to me, so we should establish a set of principles and use Objective-C for both libraries! As I explained above, you are not resolving "random exceptions" in favor of a consistent paradigm; rather, you are doing precisely the opposite. Instead of deciding to use parts based on a single rational rule (use parts when you need to), you are establishing a set of circular principles founded on unsubstantiated and unclear definitions derived from inaccurate interpreting of evidence. 4. "No" costAs per usual, you seem to be perfectly content disregarding the simplicity, elegance, and consistency of a codebase in favor of a simplistic approach based on your own "conceptual" interests. Throughout the development of Cogent Core, you have vehemently rejected every new simplification and improvement of the codebase due to a refusal to understand that the primary issue with your code is nothing but the sum of these abundant decisions to introduce additional complexity for no logically substantiated reason. Having to understand the additional concept of parts, prefix tons of things with parts, decide whether something should have parts, and guess whether we made something have parts are all additional and unnecessary cognitive burdens that impair people from efficiently and effectively writing powerful, fast, and elegant cross-platform apps. |
Beta Was this translation helpful? Give feedback.
-
Interim summaryThe crux of the debate is about the nature of the type hierarchy: whether there is a meaningful distinction present in the types, that captures the distinction between "basic" and "container" widgets. Kai's taxonomy:Kai's general point is "Widgets are widgets and children are children"
Randy's taxonomy:Randy's general point is that the type hierarchy should reflect the distinction between Basic and Composite widgets.
|
Beta Was this translation helpful? Give feedback.
-
The case in favor or using
Parts
for basic widgets1. There is a widely-recognized distinction between "basic" widget elements vs. "container" widgets
Qt: https://doc.qt.io/qt-6/widget-classes.html -- sub-headings are "Basic Widget Classes" that include Button, Label, Menu etc. vs. "Organizer" widgets
Material Design: https://m3.material.io/components -- "actions" vs. "containment"
This difference is clear in the Go type system, with basic types such as
float32
andint
, and container types such asslice
andmap
. Likewise, a basic widget represents a basic type (Spinner
,TextField
,Switch
for numeric, string, and bool types, respectively), whileSliceView
andMapView
represent the container types. In general, we have most of the basic types incore
and most of the container types inviews
.2. It is conceptually useful to capture this distinction in the software
Using
Parts
encapsulates the implementation of basic widgets, and presents the basic widget as a clear single primary entity that has all the properties a programmer should care about exposed on the main widget, while the Parts are clearly delineated as being parts of a basic widget, but not first-class user-facing widget elements themselves. It is clear that they are fully managed by the main widget.Composite widgets are obviously containers of basic elements, and are based on
Layout
orFrame
, while basic elements are based onWidgetBase
orBox
.The hierarchical organization of containers of basic elements is a universal and helpful conceptual way to organize the space of widgets, and it makes sense to have this reflected in the type hierarchy of the software. The software should reflect the natural ontology of the space of things it implements.
There is an analogy in programming languages: some languages prefer a fully generic approach without any distinction between anything -- everything is an "object" (JavaScript) or a "list" (lisp etc). But in reality, different types have different properties and natural affordances, along the same lines as widgets: basic elements such as a
float
orint
are fully self-contained, while containers such as slices and maps are expected to manage and organize collections of basic elements. Trying to stuff everything into one box creates confusion because some concepts apply to one thing and not another, and "duck typed" languages vs. strongly typed languages clearly demonstrate the advantage of establishing clear principles for "what is what" and enforcing these constraints.Fundamentally, concrete conceptual categories help people organize a space and reason about the relationships among entities in the space. A container is primarily concerned with laying out and organizing the interaction among a set of basic elements, while a basic element is primarily concerned with supporting a single basic function (e.g., text entry, representing a bool value, triggering an action etc).
3. Parts are necessary in some cases, and it makes sense to just be consistent instead of having random exceptions
Some widgets have both container and basic roles, e.g.,
TreeView
, and thus require both Parts and Children.Instead of treating these cases as random exceptions, it makes more sense to establish a clear, consistent sent of principles:
Parts of basic widgets go in Parts
Components of container widgets go in Children.
4. There is no meaningful cost to using
Parts
The implementation is essentially identical except for the names used in the Config.
This also highlights the point that the case in favor of Parts is entirely about the conceptual, design-oriented benefits listed above, and not about strong implementational considerations: you can do it either way.
The case against
@kkoreilly please make your case, addressing specifically the points raised above.
Beta Was this translation helpful? Give feedback.
All reactions