<p>I kind of like the idea of interacting &quot;black boxes&quot; that have well-defined interfaces and hidden internal state.</p>
<p>Are there any programming languages that specifically encourage this sort of program design (I believe, the term is &quot;Component-Based&quot; or &quot;Component-Oriented Programming&quot;)? I understand that you can do this in pretty much any languages, especially OOP-languages like Java or C# have all the tools available, but they typically come with a whole arsenal of other stuff and are multi-paradigm, so they just happen to support this paradigm as well.</p>
<p>Are there languages that are CBP/COP-first?</p>

<language-design><language-comparison>
Are there languages geared towards component-based design?
CC BY-SA 4.0
2024-09-14T08:23:22.957Z
Is there a difference between component-based design and object oriented design?
mousetail 'he-him'
CC BY-SA 4.0
2024-09-14T09:07:26.020Z
In OOP you have inheritance, so you build a hierarchy of classes and you have to know how parent class operates in order to properly use it in your own class. In CBP you have interfaces and you combine things together instead of extending them. Imagine a Java class that is `final` and only has : 1) an interface in the form of `public` methods (no public access to fields!) 2) `private` fields that represent internal state, totally hidden from the "outside world" 3) maybe some `private` methods that serve as utility functions.
xaxa
CC BY-SA 4.0
2024-09-14T09:32:41.607Z
There are many OO languages without (classical) inheritance, and there are paradigms that incidentally enforce total encapsulation, like the actor model, or really any message-sending OOP; are those in scope, or is an explicit focus on component-orientation in the design what you're looking for (and if so, do  component-based systems avant la lettre like Oberon count too)? I can't speak much to the overall contents, but at the least [Peter Hans Fröhlich's PhD thesis](http://oberon2005.oberoncore.ru/paper/pf2003.pdf) ought to be very relevant, albeit twenty years old.
Michael Homer
CC BY-SA 4.0
2024-09-14T09:34:41.667Z
The short answer to the title question is definitely "yes", I'm just trying to suss out the boundaries here.
Michael Homer
CC BY-SA 4.0
2024-09-14T10:22:52.467Z
@MichaelHomer I'm sorry, I don't think I'm competent enough to be more specific, so I'd be interested to know more about the possible options :) Actor model and message-sending OOP, from what I know about them, both seem to fit my criteria. So if you could name a couple of languages that follow these paradigms... Basically, yes, I'm looking for languages that treat encapsulation, composability and separation of concerns as primary way to write code. Thanks!
xaxa
CC BY-SA 4.0
2024-09-14T10:24:09.697Z
Think of something like "microservice-architecture" but within a language.
xaxa
CC BY-SA 4.0
2024-09-14T11:25:39.720Z
Would the obvious example of [Modula-2](https://en.wikipedia.org/wiki/Modula-2) (and its predecessor [Mesa](https://en.wikipedia.org/wiki/Mesa_(programming_language)) and successors [Modula-3](https://en.wikipedia.org/wiki/Modula-3), [Oberon](https://en.wikipedia.org/wiki/Oberon_(programming_language)), &c) count?  That pre-dates widespread OO support, but is strongly aimed at modular programming.
gidds
CC BY-SA 4.0
2024-09-14T11:26:28.737Z
I agree with Michael Homer that this sounds quite like the actor model, and also "message-passing" OOP (minus inheritance). If the reason you exclude languages like Java is because are multi-paradigm, then some of the older "pure OO" languages are probably still in bounds.
kaya3
CC BY-SA 4.0
2024-09-15T09:43:42.180Z
Perhaps I'm missing something - but [Rust](https://www.rust-lang.org/) strikes me as the canonical popular example here. You define `trait` interfaces and explicitly `impl` them on types. These function by composition and in stark contrast to inheritance. Quite a lot of thought has been given to having well-defined "coherent" interfaces and such, though I would imagine less than some other more focused languages.
apropos
CC BY-SA 4.0
2024-09-16T11:22:39.307Z
@apropos Rust doesn't really "encourage" you to use traits, nor to encapsulate type members.
kaya3
CC BY-SA 4.0
2024-09-19T22:37:44.007Z
Isn't this what the Ada designers envisioned? The goal was to be able to have teams of programmers where the users of a module were just given the input/output specs, and the implementors were given the contract.
Barmar
CC BY-SA 4.0
2024-10-19T02:39:48.870Z
@kaya3 late responding to this, but I'd somewhat disagree: functions not being accessible out of their module by default, structs needing `pub` indicators per-field, and there being no way to express code that is generic over the *behavior* of a type w/o traits (think a `<T>` that expresses that *some* functions are available on `T`) all strike me as encouraging the use of traits and encapsulation.
apropos
CC BY-SA 4.0
2024-10-19T02:40:01.860Z
Though I think I would also argue that Standard ML is a valid answer to this question, so take that as you will :-)
apropos
CC BY-SA 4.0
2024-12-19T16:03:28.197Z
As the answers show, you need to describe what you mean by a component. I've seen a book entitled 'Component-based software design in C# and Java' that just assumed components are objects and didn't mention components at all. A C# component is more or less a Java Bean and they are much more than just an object. Is that the notion of component you're referring to?
reinierpost
<p>This question is somewhat asking two different things:</p>
<ul>
<li>are there languages aimed at supporting component-oriented programming;</li>
<li>and are there languages with certain modular encapsulation properties</li>
</ul>
<p>The answer to both questions is yes, but I think the idea that either implies the other is mistaken. <a href="https://langdev.stackexchange.com/a/4066/133">Eric Lippert has pointed out that</a> C♯ was explicitly geared towards component-based design... but you've already ruled that out as an instance of what you're asking about! We will find both languages that aim to support component-based design and those that have the combination of (absences of) features you're looking for. I also have a couple of notes about languages that are geared towards components <em>by</em> building around the sorts of features you want to avoid.</p>
<hr />
<p>In the comments you refined the details of what you intended a bit further:</p>
<blockquote>
<p>In OOP you have inheritance, so you build a hierarchy of classes and you have to know how parent class operates in order to properly use it in your own class. In CBP you have interfaces and you combine things together instead of extending them.</p>
</blockquote>
<p>There are plenty of object-oriented languages that don't have (classical) inheritance, so we can look to those. I'd even argue that &quot;in OOP you have inheritance [and] classes&quot; is false in itself.</p>
<p>For example, <a href="https://en.wikipedia.org/wiki/Prototype-based_programming" rel="noreferrer">prototype-based languages</a> do not inherently require privileged access to a parent in their inheritance model — in fact, it tends to be a more obvious issue to provide that in them, leading to the &quot;vampire problem&quot; (although many do anyway, because it's either helpful or desired by users). Without privileged access, these parent pointers amount to assistance using the public interface of another object to &quot;favour composition over inheritance&quot;.</p>
<p>You went on further with:</p>
<blockquote>
<p>Imagine a Java class that is final and only has : 1) an interface in the form of public methods (no public access to fields!) 2) private fields that represent internal state, totally hidden from the &quot;outside world&quot; 3) maybe some private methods that serve as utility functions.</p>
</blockquote>
<p>There are also plenty of object-based languages and programming models that have this sort of hard encapsulation boundary. In particular, it is very common in languages designed with distributed systems in mind, but it's also a pure realisation of the message-passing model of object orientation.</p>
<p>A fairly clean example of all this is the <a href="http://erights.org/" rel="noreferrer">E language</a>. Objects in E are conceptually isolated and entirely self-contained. &quot;Fields&quot; are lexically-captured variables, invisible through an object reference. It has no inheritance, instead supporting what it calls &quot;delegation&quot; to the <em>public</em> interface of other objects as ordinary method calls (the form <a href="https://doi.org/10.4230/LIPIcs.ECOOP.2016.13" rel="noreferrer">Jones et al. identified as &quot;forwarding&quot;</a>, to contrast with JavaScript-style &quot;delegation&quot; that preserves identity; preserving identity enables downcalls, which <em>can</em> couple parent and child more closely). Each object can then be treated as a component, its public interface defining exactly what can be done with it by clients. <a href="https://www.emeraldprogramminglanguage.org/authorsVersion.pdf" rel="noreferrer">Emerald</a> was an earlier distributed language with similarly-strong object-level encapsulation, no classes, and no inheritance, which influenced a lot of subsequent work.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Actor_model" rel="noreferrer">Actor model</a> in general tends to have this property: there is no communication between objects but messages sent to the receiver's inbox, so the public interface is the only access to the object and covers all the functionality it can provide. Some actor systems have classical inheritance, and so might fall foul of the first criterion, but many don't.</p>
<p>There are also non-distributed languages that start from the same point, and it's not especially uncommon. Message-passing OO is one of the primordial forms of object orientation, so there have been many instantiations of it and often without classical inheritance. In these systems an object <em>is</em> an identity that can receive messages and decide what to do in response to them. The only form of interaction between different pieces of code is such a message send, so no other leaks can occur. The public interface is the set of messages that an object plans to understand, and there's no access to the implementation beyond that.</p>
<hr />
<p>Outside of object systems, languages like Wirth's Modula-2 provide strong encapsulation at the module level. Nothing from inside a module is available from the outside unless explicitly exported (and explicitly imported on the other end). Any module defines a self-contained component from the perspective of other code; it is possible to choose to export a mutable field, which may not meet your requirements here, but it is always an explicit decision. Its follow-up Oberon added more OO facilities and gets closer to the conceptual COP model, before the name was coined. An explicitly component-based spinoff by way of Oberon was <a href="https://blackboxframework.org/index.php?cID=home,en-us" rel="noreferrer">Component Pascal</a>.</p>
<p>Many language families have strongly-encapsulated modules, including ML, which seem like they provide for component-based design just as much as the object-based systems do. It's not often talked about this way, but Haskell would tick off all of your listed boxes for a component-based language. This may be a sign that the terminology is still under-defined here, because I don't think these sorts of language are really what you were thinking of.</p>
<hr />
<p>There are some specifically component-oriented language designs that probably meet all your requirements, or at least raise questions about tweaking them. [Peter Hans Fröhlich's PhD thesis is titled <a href="http://oberon2005.oberoncore.ru/paper/pf2003.pdf" rel="noreferrer">Component-Oriented Programming Languages: Why, What, and How</a> and he makes some similar points to you here. As part of it, he designs a language called Lag<em>oo</em>na, which draws together all of the points above from other languages. The thesis is pretty accessible and worth a read if you're interested in this area, and chapter 5 sets out the language design.</p>
<p><a href="https://doi.org/10.1145/2166929.2166932" rel="noreferrer">Exil</a> is a Smalltalk-based component-oriented design, with perhaps not quite as much heft behind it but a more explicit component design with explicit inter-component message ports. This is lifting one style of component design into the language level, but it's possibly not the one you're looking for.</p>
<p>There are a number of others of greater or lesser significance, although not many that made it to the mainstream.</p>
<hr />
<p>There is also a relationship here to the &quot;<a href="https://doi.org/10.1145/1060710.1060716" rel="noreferrer">Lego hypothesis</a>&quot;, that software can be assembled out of many small predefined components, which goes back in different terms at least to <a href="https://www.cs.dartmouth.edu/%7Edoug/components.txt" rel="noreferrer">McIlroy's &quot;Mass produced software components&quot;</a> in 1969. This has been an aspiration and a goal for many people and many language design projects; I don't think any claim to have accomplished it, and I'm not sure anybody truly believes in the strong version of it (it's empirically false in existing languages). However, there are many languages that try to get closer to the ideal of component-based program construction, and many more that incidentally provide what you're looking for without necessarily having that label on it.</p>
<p>As well as those points, there are different conceptions of &quot;component&quot; that lead to different results. Something like <a href="https://tidsskrift.dk/daimipb/article/view/7654/6510" rel="noreferrer">gbeta</a> could be said to be designed for the creation of well-designed, separable, safely interacting components — but it's <em>very</em> heavily built around inheritance as a construct! I think equating broad features, or their absence, with component-based design is probably an error, and it's better to talk specifically about what we're actually looking for rather than lumping different pieces together, because we'll all have slightly different ideas of what that means.</p>

CC BY-SA 4.0
2024-09-16T03:17:18.410Z
2024-09-16T03:17:18.410Z
Michael Homer
<blockquote>
<p>Are there any programming languages that specifically encourage this sort of program design (I believe, the term is &quot;Component-Based&quot; or &quot;Component-Oriented Programming&quot;)?</p>
</blockquote>
<p>Yes. The second paragraph of the C# 1.0 specification is</p>
<blockquote>
<p>C# is an object-oriented language, but C# further includes support for
component-oriented programming. Contemporary software design
increasingly relies on software components in the form of
self-contained and self-describing packages of functionality. Key to
such components is that they present a programming model with
properties, methods, and events; they have attributes that provide
declarative information about the component; and they incorporate
their own documentation. C# provides language constructs to directly
support these concepts, making C# a very natural language in which to
create and use software components.</p>
</blockquote>
<hr />
<blockquote>
<p>OOP-languages like Java or C# have all the tools available, but they typically come with a whole arsenal of other stuff and are multi-paradigm, so they just happen to support this paradigm as well. Are there languages that are CBP/COP-first?</p>
</blockquote>
<p>As the spec clearly says on the first page, C# 1.0 was designed from the ground up to create and use components: packaged-up functionality with clear interfaces, that can be versioned over time and describe themselves. C# is a component-first language, by design.</p>
<p>That whole &quot;arsenal of other paradigms&quot; -- generic typing, null safety, query comprehensions, dynamic dispatch, and so on -- got added later.</p>
<hr />
<p>I'll take this opportunity to note also that the things which make languages suitable for component-oriented software design are often not actually <em>language</em> features per se. The entire .NET <em>framework</em> that underlies C# was designed to be component-oriented. Having such a strong bias from the framework has both advantages and challenges for the language designer.</p>

CC BY-SA 4.0
2024-09-14T19:23:09.750Z
2024-09-14T23:29:21.157Z
2024-09-14T23:29:21.157Z
Eric Lippert
<p>I am surprised that no one has mentioned the ML family of languages and their extremely expressive module system, which gives you powerful ability to encapsulate and abstract components. Especially, OCaml provides further extensions such as applicative functors, recursive modules and first-class modules that make the module system even more powerful.</p>
<p>In ML, a <em>module</em> contains data (including functions) and types, and a <em>signature</em> is a specification (or contract) for a module. For example, in OCaml one might write:</p>
<pre class="lang-ocaml prettyprint-override"><code>module type Stack = 
  sig
    type 'a stack
    val empty : 'a stack
    val push : 'a -&gt; 'a stack -&gt; 'a stack
    val pop : 'a stack -&gt; ('a * 'a stack) option
  end
</code></pre>
<p>as the specification for a stack. Then, one might implement a stack in many ways, for example as a list:</p>
<pre class="lang-ocaml prettyprint-override"><code>module List_Stack : Stack =
  struct
    type 'a stack = 'a list
    let empty = []
    let push a s = a::s
    let pop s = 
      match s with [] -&gt; None | t:l -&gt; (t, l)
  end
</code></pre>
<p>Note that this is just but one implementation of <code>Stack</code>. Whenever a stack is needed, any valid implementation of the <code>Stack</code> signature (i.e. interface) can be used.</p>
<p>Furthermore, ML modules are <strong>compositional</strong>, and this is where ML really shines. Which means that one can write <em>functors</em> which are modules that take other modules as arguments. For example, a generic hash map that takes any hashable type as key:</p>
<pre class="lang-ocaml prettyprint-override"><code>module type Hashable =
  sig
    type t
    val hash : t -&gt; int
  end

module type HashMap = 
  functor (Key : Hashable) -&gt;
    sig
      type key = Key.t
      type 'a map
      type add : key -&gt; 'a -&gt; 'a map -&gt; 'a map
      type lookup : key -&gt; 'a map -&gt; a
    end
</code></pre>
<p>This lets you reuse and compose components at will, and to plugin different implementations of the same components easily.</p>
<p>These are the basics of a ML-style module system. OCaml also support some extensions to this system, making its module system extra powerful:</p>
<ul>
<li><em>recursive modules</em>, which allow for cyclic and mutual dependencies between components;</li>
<li><em>first-class modules</em>, which allow one to write functions that take modules as arguments or return modules, so that a programmer could select an implementation between multiple valid implementations at runtime based on input.</li>
</ul>
<p>Overall, ML modules are an extremely powerful tool for component-based design, and can express modular designs impossible in other programming paradigms. However, as far as I know, only two ML family languages, Standard ML and OCaml, have full-fledged ML-style module systems.</p>

CC BY-SA 4.0
2024-10-26T09:13:58.397Z
2024-10-26T09:13:58.397Z
xuq01
<p>The usual term for “black boxes that have well-defined interfaces and hidden internal state” is <strong><a href="https://en.wikipedia.org/wiki/Modular_programming" rel="nofollow noreferrer">modules</a></strong>. The first language that codified modules was <a href="https://en.wikipedia.org/wiki/CLU_(programming_language)" rel="nofollow noreferrer">CLU</a>. CLU was never industrially successful, but it established many interesting concepts. Barbara Liskov's <em><a href="https://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-561.pdf" rel="nofollow noreferrer">A History of CLU</a></em> is worth a read (also <em>A Note on CLU</em> by Liskov 1975 and <em>Abstraction mechanisms in CLU</em> by Liskov et al in Commun. ACM 1977). After CLU, the main driver for module systems and abstract types in programming languages is ML (both in Standard ML and Caml strands).</p>
<p>If you want to look at a language with a module system and not a lot of other sophistication in its type system (in particular no objects or classes), look at <a href="https://en.wikipedia.org/wiki/Standard_ML" rel="nofollow noreferrer">Standard ML</a>.</p>

CC BY-SA 4.0
2024-10-06T17:02:32.787Z
2024-10-06T17:02:32.787Z
Gilles 'SO- stop being evil'
<p>You could argue that UML fulfills the requirements. UML has a number of design functions which can be expressed in a graphic language, as well as a in more traditional type of text language. UML defines a one-to-one translation between the text version and the graphical version.</p>
<p>There are translators that can translate to and from traditional programming languages, at least in some problem domains. In theory you could program a full system using only UML, although I believe it is seldom done.</p>
<p>The different diagrams in UML basically falls into two categories: structure and behavior.</p>
<p>The structure diagrams (either as graphical diagrams or as text descriptions) can describe things like (there are a few more):</p>
<ul>
<li>classes (translates directly to classes in OOP programming languages)</li>
<li>objects (actual instances, most often of classes)</li>
<li>packages (how code parts are packaged together, as example into and application or a supporting library)</li>
<li>deployment (how code is deployed when several computers are used).</li>
</ul>
<p>The behavior diagrams (as well as their text versions) describe things like:</p>
<ul>
<li>use cases (how things external to the system uses it)</li>
<li>activities (how activities interact)</li>
<li>state machine diagram (state machines are often used in certain domains)</li>
<li>sequence (the sequence between different actions / happenings)</li>
<li>timing</li>
</ul>
<p>In real-world usage, UML seems to mostly used as a high-level design language. The design is then translated more or less manually into an actual programming language. But as managed there are tools that allow you to create source code directly from the diagrams. Given a set of rules the tools allow you to translate from actual source code inte UML for further refinement and later translated back to source.</p>

CC BY-SA 4.0
2024-10-17T21:32:02.430Z
2024-10-17T21:32:02.430Z
ghellquist
<blockquote>
<p>I kind of like the idea of interacting &quot;black boxes&quot; that have well-defined interfaces and hidden internal state.</p>
</blockquote>
<p>I liked the idea of Santa Claus when I was a child too.</p>
<p>A &quot;black box&quot; <em>means</em> an ill-defined and poorly-understood thing, so you've already stated a contradiction and as such this answer is about to be a frame challenge.</p>
<p>I've never - <em>never</em> - in my life encountered a man-made machine where you know strictly what inputs it accepts and strictly what outputs can arise from those inputs (the &quot;interface&quot;), but somehow you don't know the part in between the input and output (the &quot;internals&quot;).</p>
<p>In software, the reality is that there is no true separation between interfaces and internals. They are the mating parts of the implementation of the workings of a machine which a software developer designs.</p>
<p>A fully-defined interface always amounts to access to a reference implementation of the internals. Everything short of that just leads to the interface being less precisely defined than is possible with a reference implementation.</p>
<p>Many usages of interfaces tolerate some imprecision. Indeed, even half-wits are capable of writing programs that are correct sometimes, so imprecise use does not always lead to total failure, but to the workings of the machine being either degraded in quality or only accidentally correct.</p>
<p>A documented interface without documented internals, typically defines some things loosely or not at all.</p>
<p>For example, the processing time from call to return is typically defined loosely and implicitly, rather than in terms of exact clock cycles - although contempt (or ignorance) of execution delay as a genuinely measurable output of an interface, is something that regularly penalises bad cryptographers.</p>
<p>But this imprecision in the description of the interface is a source of complexity, error, and unpredictability, not something to be desired for its own sake.</p>
<p>Imprecision often has to be accepted when no one developer can understand every detail of the entire workings of a very complicated machine. The challenge of good interface design then, is to design interfaces in ways that the imprecision relates only to matters which are irrelevant to the client of the interface.</p>
<p>That is, the designer of the interface needs to have an idea of what aspects of the internals behind the interface concern crucial behaviour on which another developer must be able to rely, and what aspects are arbitrary and can be varied without damaging another's reliance.</p>
<p>This is completely the opposite of &quot;black boxes&quot; and &quot;hidden internals&quot;. It requires clear glass boxes whose contents are reasonably obvious. It requires developers who are still somewhat involved in each others' work and working from a somewhat shared understanding.</p>

CC BY-SA 4.0
2024-09-14T18:46:16.103Z
2024-09-17T20:28:16.660Z
2024-09-17T20:28:16.660Z
Steve
CC BY-SA 4.0
2024-09-14T23:25:50.947Z
The question asked for examples of languages that meet a certain design criterion. This answer makes no attempt to answer the question that was asked, but instead goes off on a rant about how a thing that the original poster enjoys is actually bad.
Eric Lippert
CC BY-SA 4.0
2024-09-15T01:10:36.137Z
Sorry, I see plenty of times where an interface is plenty without knowing details of how it's implemented. UI controls for example. It obeys the spec as to how it's created, how it's initialized, when it redraws. I, as a programmer, do not need any knowledge at all of how it is implemented. Depending on what I am writing, I might not even need knowledge of how it presents to the user.
SoronelHaetir
CC BY-SA 4.0
2024-09-15T06:28:30.720Z
@EricLippert, I deny that "black boxes with *well-defined* interfaces" exist. Rather, the blacker the box, the more loosely or ill-defined the real interface. Often with these things, the concept of the "interface" itself is defined in an artificially narrow way to consist only of the data types of the members, arguments, or results - I mention the example of *execution time* of a call which is rarely considered part of the explicit interface in these discourses, but is always somewhat relevant (and extremely relevant in cryptography). (1/2)
Steve
CC BY-SA 4.0
2024-09-15T06:28:33.610Z
Nobody says one interface where you wait a second for results, another where you wait a week, and a third where there is the possibility of no return at all, are all the "same interface", just because the method signatures say they all take an int and return an int, because profile of behaviour in the round is completely different. (2/2)
Steve
CC BY-SA 4.0
2024-09-15T06:38:37.937Z
@SoronelHaetir, that's not my point. As I say, many usages of interfaces tolerate sloppiness - and the world is rife with crap, buggy, flawed software. I often use interfaces of complex software whose internals I don't remotely understand - often, there's a small space of behaviour which from experience I know works for my purpose, and hope will remain consistent into the indefinite future. But they're not thereby "well-defined" - they're an ill-defined thing which I merely hope someone else has designed intelligently to anticipate my usage and behave sensibly in relation to my usage.
Steve
CC BY-SA 4.0
2024-09-15T07:00:03.910Z
This might be a fine answer to a question about component-oriented programming on a *different* site (Software Engineering?), but it doesn't have anything to do with *this* site's topic. If it concluded with "therefore no such languages exist" then it would, strictly, be an answer to this question, but it presently doesn't even go that far.
Michael Homer
CC BY-SA 4.0
2024-09-15T07:35:00.973Z
@MichaelHomer, it must have something to do with this site's topic if a person, to introduce their question, alleges the existence of something I'm saying doesn't exist and is a contradiction in terms (for reasons that can't be summarised in a comment). I realise the OP was not asking about the issue I've raised, presumably because they assumed it was an uncontroversial starting point, but this answer is addressing that flaw in their premise. I'm less inclined to say that "no such languages exist" - rather, that languages do exist which facilitate the OP's faulty thinking about interfaces.
Steve
CC BY-SA 4.0
2024-09-15T08:54:46.533Z
This answer seems hung up on an overly restrictive definition. There are tons of abstract things out there that are still well defined but have no single, concrete reference implementation. Do iterators not exist as a well defined thing? Are sets ill-defined because their order is not defined? Just because an interface does not specify every inconsequential detail doesn’t make it imprecise, just abstract. People don’t need "abstract" to write bad, sloppy code and there are many useful, good abstractions.
MisterMiyagi
CC BY-SA 4.0
2024-09-15T10:03:15.443Z
@MisterMiyagi, my argument is not that every internal detail always counts in every case. My argument is that every detail always counts in some case. Or speaking even more precisely on the point, that there are no general class of details, which would be important to know of or discuss amongst ourselves as a general class, which never count in any case. Software developers have to make informed decisions in the context about what counts and what doesn't. (1/3)
Steve
CC BY-SA 4.0
2024-09-15T10:03:54.440Z
My argument is also that there are a large class of details which are not in fact free to be varied arbitrarily, but have acceptable ranges of behaviour, even if it can be easily shown that no one specific behaviour is always required. These constraints are themselves usually ill-defined and usually implicit, but are certainly there. I gave the example of execution time - it is rarely constrained to an exact number of clock cycles, but there is usually a range of acceptability, and the actual execution time is determined by the internals. (2/3)
Steve
CC BY-SA 4.0
2024-09-15T10:09:57.430Z
Also my argument is not against using abstractions. It is against people becoming so familiar and ensconced with these abstractions, that they forget there is a wider reality where these abstractions do not properly apply, or that there are important aspects of very routine problems which they do not cover. The consequence appears to be that they lose (or do not even acquire) the knowledge and skill to make an informed decision in the first place about what matters and situations the abstractions do and do not properly apply to. (3/3)
Steve
CC BY-SA 4.0
2024-09-15T20:59:27.610Z
This sounds like a great blog post; it's not an answer to the question that was asked, and so doesn't belong here.
Eric Lippert
CC BY-SA 4.0
2024-09-16T11:29:21.297Z
*"I've never - never - in my life encountered a man-made machine where you know strictly what inputs it accepts and strictly what outputs can arise from those inputs (the "interface"), but somehow you don't know the part in between the input and output (the "internals")."* ─ Have you never used `Array.prototype.sort` in JavaScript, then? Sure, you can go and read about how it's implemented in various JS engines, but you don't have to in order to use it, and if you are programming for the web then you really *don't* know in advance which implementation will be in use.
kaya3
CC BY-SA 4.0
2024-09-16T11:48:23.750Z
@kaya3, but it's possible to use things you don't properly understand, and which are ill-defined. The mere use of things doesn't thereby establish that they must be well-defined. And definition is not a binary state, but a matter of precision. Lots seems to be made of the fact that internals behind the interface can be varied - but that latitude exists often as much because the interface is *not* well-defined, rather than because it is well-defined. That's typically why viruses have been introduced into open source libraries - everyone keeps pretending the interfaces are well-defined.
Steve
CC BY-SA 4.0
2024-09-16T12:04:51.827Z
@Steve I don’t think anyone here is trying to deny interfaces are defined and used badly at times. Rather the issue is the *categorial* statement in the answer that by leaving *any* detail undefined an interface is *inherently* not well-defined.
MisterMiyagi
CC BY-SA 4.0
2024-09-16T13:33:25.990Z
If your opinion is that `Array.prototype.sort` is ill-defined, then you should make a comment to the TC39 that you have found a mistake or omission in [its specification](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.sort).
kaya3
CC BY-SA 4.0
2024-09-16T15:03:34.823Z
@MisterMiyagi, I am tending towards that position, yes, that leaving details undefined means the details are not well-defined.
Steve
CC BY-SA 4.0
2024-09-16T15:11:43.733Z
@kaya3, well I've already repeatedly mentioned latency and execution time as an often-overlooked aspect of interface behaviour, and I see no mention of that in your specification (although I'm prepared to be corrected, since I am not familiar with that long document). To give you an idea where this regularly counts for practical software design, it's when calls are local versus those being remoted over a network connection.
Steve
CC BY-SA 4.0
2024-09-16T16:22:20.187Z
@Steve That seems infeasible. You *cannot* define everything completely - in the end how something actually behaves will depend on the compiler, the dependencies, the OS, the arch, possibly the make and build of the hardware (yes, we got hit by that in practice). Saying that a concrete *code* implementation is well-defined is just picking an arbitrary level. The entire point of programming languages is to make abstractions and those will never be defined down to every detail.
MisterMiyagi
CC BY-SA 4.0
2024-09-16T17:49:39.727Z
You said: *"I've never - never - in my life encountered a man-made machine where you know **strictly what inputs it accepts and strictly what outputs can arise** ..."* (emphasis mine). Latency and execution time do not affect what inputs it accepts or what outputs can arise, so this doesn't fall under your claim. Nonetheless, the specification of `Array.prototype.sort` *correctly* doesn't promise anything about how long it will take, because that genuinely *isn't* known in advance.
kaya3
CC BY-SA 4.0
2024-09-16T17:52:47.587Z
If you want to say that means the behaviour is uncertain then fine, but "uncertain" does not mean "ill-defined". It just means that the latency or execution time is not part of the specified behaviour and can't be strictly relied on by the programmer. In the same way that iteration order of a hash table is not part of its specified behaviour and can't be strictly relied on. Something can only be reasonably called "ill-defined" if its purported definition is unfit for purpose.
kaya3
CC BY-SA 4.0
2024-09-16T18:03:50.730Z
@MisterMiyagi, I'm not arguing that this stops at the code internals  I agree the hardware itself can come into it, so can physics. However I'm not sure your tone suggests you're about to integrate this realisation you've made that nothing is well-defined, and therefore champion my argument against the contradiction of "black boxes with well-defined interfaces". I'm not suggesting interfaces need to be well-defined - you're setting that standard for yourself, which I think is unattainable.
Steve
CC BY-SA 4.0
2024-09-16T18:37:28.093Z
@kaya3, but execution time *is* a measurable output. You're lawyering with me now, suggesting that this output isn't one that meets your criteria of an output, when my case is precisely that this lawyering is self-deceptive and self-indulgent, and fails to engage with bread and butter realities of software design, such as that *performance always matters*, and the only question is *how much* it matters. Nobody makes an interface call just to have the computer whirr away for a thousand years. (1/2)
Steve
CC BY-SA 4.0
2024-09-16T18:39:26.653Z
I agree that it is only reasonable to call something ill-defined if the definition is unfit for purpose. And I'm saying black box interfaces in general are unfit for the everyday purpose of practitioners writing correct and reliable software. Moreover, it is equally unfit for theorists to keep talking amongst themselves about "well-defined interfaces", because such language encourages you to habitually ignore (or treat as nugatory) all the ill-defined parts of interface behaviour which are actually of central importance for real practitioners when they design software or use interfaces. (2/2)
Steve
CC BY-SA 4.0
2024-09-16T20:36:40.330Z
@Steve I don’t think that something must be completely defined to be well-defined. As mentioned before I do consider abstract things perfectly well-defined. If you think the two *must* be equivalent, it’s probably more productive to agree to disagree.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T04:16:37.203Z
@MisterMiyagiz I too don't think something must be completely defined to be well-defined. I just think all the *important* things have to be defined for something to be well-defined.
Steve
CC BY-SA 4.0
2024-09-17T05:34:03.707Z
@Steve Well clearly we disagree on what is important then. Sure one might care for things like speed *overall*, I.e. when choosing concrete components, but most *individual* pieces don’t have to prematurely enforce that they only work with fast black boxes - and yes, we got bitten by misguided performance requirements in practice too. Tacking something like performance onto the concept of "sorted array" is wrong. Sure one might need something that is both fast and sorted at times, but it does not make the concept of just sorted ill defined.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T05:45:50.740Z
@MisterMiyagi, I'm just giving execution time as an example to demonstrate my *point* which is that you *systematically* ignore things about the behaviour of implementations which are considered generally important to software design in practice, and you react stubbornly and defensively when it is pointed out how simplistic and unreal are the tenets you are proceeding from. I'm not seeking advice about when or to what degree performance is important - those are questions which I would decide in the context of a specific application. I'm simply pointing out your emperor is wearing no clothes.
Steve
CC BY-SA 4.0
2024-09-17T05:54:34.463Z
@Steve Ignoring parts is the whole point of abstraction. You don’t have to point it out, it’s literally what the word means. Likewise for black box and interface. To make a decision in the context of a specific application or even environment, not an isolated piece of code, is exactly what these concepts are there for.  The emperor doesn’t wear any clothes because he didn’t dress yet, not because he didn’t notice the breeze.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T06:00:07.607Z
@MisterMiyagi, I think I responded to a previous iteration of your comment above. I haven't specifically said the concept of a "sorted array" is ill-defined. I'm talking about the approach generally of separating programs into "interfaces and internals", and whether interfaces which *conceal* the internals (or where implementors reserve the right to vary the internals "freely") can ever be "well-defined" interfaces. In my view, the interface of a *method* which sorts an array is ill-defined in an important and everyday respect, if there is no constraint on execution time.
Steve
CC BY-SA 4.0
2024-09-17T06:12:20.353Z
@MisterMiyagi, the point of designing abstractions is to ignore the parts of a problem which are *unimportant* in practice, whilst bringing narrower focus onto what is important. My position here is that you are systemically ignoring the *important* parts of software development too - that you are abstracting in an incompetent and out-of-touch way, which causes your own confusion and leads you to a proliferation of absurd claims that are inapplicable to the reality of how software is designed. (1/2)
Steve
CC BY-SA 4.0
2024-09-17T06:14:34.033Z
The organisation of code into interfaces and internals (which is a very standard practice amongst developers, regardless of the language in use) does not require the internals to be concealed from anybody and a "black box" produced, it does not require that the interface standing in isolation be wholly "well-defined", and it does not require that the internals behind the interface should be variable "freely". There is no "abstraction" that requires these claims to be made - claims which don't correspond to the interfaces of any real software. (2/2)
Steve
CC BY-SA 4.0
2024-09-17T06:57:00.840Z
@Steve I really have no idea what makes you think you are in a position to say what I (or perhaps people like me) are systematically ignoring or are incompetent about or out of touch. It’s a reality that much code is more general than any specific program and only applies to abstract requirements. Every library targeting "iterators", or "awaitables" or one of the many, many useful abstractions out there is written without a concrete implementation of that black box that one could peek into. This has nothing to do with concealing things and is very much part of real software.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T07:04:05.183Z
That you have *specific* problems with *specific* cases does not make the concepts or the people using them bad by itself. I haven’t encountered any notable concept, paradigm or language that no one used badly.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T07:53:58.197Z
@MisterMiyagi, my issue isn't whether all these "useful abstractions" exist - it's whether their interfaces (taken standalone) are well-defined or not. I've already been quite clear that developers are quite capable of using *ill-defined* things - I write ill-defined interfaces all the time, and I often vary their implicit behaviour subsequently too - so the mere use of interfaces does not establish that they must be well-defined. If standalone interfaces were only very rarely ill-defined, I might cede the point, but on the contrary I think ill-definition is the rule.
Steve
CC BY-SA 4.0
2024-09-17T08:01:21.250Z
@Steve Then we are back at square one at which I have no idea what criteria you apply for well- or ill-defined. Or for that matter why you go the extra mile to declare every black box ill-defined per se, or some of the other categorical claims.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T09:38:46.503Z
@MisterMiyagi, I'm applying the same criteria as you do - an interface is well-defined when the internals can be a black box, varied freely by the author, and nobody using the defined interface would care about the obscurity of the internals or have reasonable cause to object to any variation in the internals. I use execution time as an example with wide applicability, where it is very rarely a defined part of the interface behaviour, but clients of the interface would often object to a radical degradation in speed, and in some cases they would even object to an increase in speed.
Steve
CC BY-SA 4.0
2024-09-17T10:27:58.733Z
@Steve And I don’t get the performance example at all. Most client code should not care about performance. The application as a whole *maybe* yes (but I have counterexamples of this being premature too) but that is not the concern of individual pieces. Most code components will work fine with slow and with fast black boxes; that  some concrete configuration of all those components and boxes has additional criteria (say, performance) does not mean that every component using an interface has to care about those criteria as well, and that not caring about them means that piece is ill-defined.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T11:16:31.083Z
@MisterMiyagi, I say with supreme confidence that the speed of execution is a generally important consideration that regularly factors in how interfaces are structured and used within software designs. Often this begins with the rules of thumb of experienced designers, such as using network calls in a non-chatty way, and designing interfaces in a way that doesn't require chattiness. I don't know what you mean by "premature". The argument I'm making is that performance profiles are rarely defined, making a standalone interface without definition of such an important matter ill-defined. (1/2)
Steve
CC BY-SA 4.0
2024-09-17T11:18:46.887Z
The fact that many interfaces "work" with slow or fast internals (in some conventionally reasonable range) is not the question here. The question is whether there is any *definition* or not of the execution time of the interface. You seem to be arguing that interfaces are "well-defined" because you have a right to ignore all the important things and everyday concerns of software developers which, if acknowledged, show that what you deem well-defined is in fact ill-defined. In other words, you define things "well" not by constraining behaviours, but by ignoring more and more things. (2/2)
Steve
CC BY-SA 4.0
2024-09-17T11:48:30.147Z
@Steve I say interfaces are well-defined if they cover everything an implementation must provide. That’s it. An interface *may* include performance beneficial things like bulk calls or complexity guarantees, but it doesn’t have to. There are tons of interfaces for which performance is not essential and omitting it doesn’t make the interface ill-defined. Ignoring something in an interface also does not mean that a *concrete implementation used in a concrete application* shouldn’t provide it if the larger usecase does require it - it only means the interface isn’t the place to define it.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T11:49:33.620Z
I also say with supreme confidence that adding a definition of performance to every or even most interfaces is premature optimisation. Many individual pieces of a software have no idea about the performance requirements of the whole thing and thus shouldn’t constraint it.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T12:40:15.353Z
@MisterMiyagi, no, there is *no* case where performance is a completely irrelevant matter for software developers. People run computers to get results, not to die waiting. I'm not arguing that maximum performance is always necessary - I'm arguing that a specification of interface performance is necessary for the interface to be "well-defined", because performance is an aspect of the behaviour of an implementation (which consists of an interface and internals), and that aspect of behaviour is one that is always important for a designer of software to consider. (1/2)
Steve
CC BY-SA 4.0
2024-09-17T12:40:36.000Z
I'm not suggesting you should add a performance specification to every interface. I'm suggesting you should accept that standalone interfaces are never well-defined - the assertion in my answer which I am defending. I have adduced the example of execution time, as something that is undoubtedly missing from almost all interface definitions. If you don't know the performance requirement of my application which uses your black box, then how dare you vary its performance? (2/2)
Steve
CC BY-SA 4.0
2024-09-17T12:55:50.300Z
If you require guarantees about performance, why are you using interfaces that don’t actually give those guarantees? Sorry, this whole situation feels like blaming mechanisms and others for - how did you put it? - that you are abstracting in an incompetent and out-of-touch way.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T13:00:49.687Z
Indeed most of my code does not require any performance guarantees and subsequently interfaces without them are perfectly well-defined. The ones that do require such guarantees also request them. I don’t see why anyone’s failure to consider that "fast X" isn’t the same as "X" makes "X" ill-defined.
MisterMiyagi
CC BY-SA 4.0
2024-09-17T13:33:18.327Z
@MisterMiyagi, because I have to rely on large libraries of code or complicated technologies written by the world's other developers, and so I use them anyway in their ill-defined condition and with their behaviours which I ill-understand, to put it bluntly. That said, the intelligence and consideration of other developers, the culture and experience I broadly share with them, and the desire of vendors to make profits, means that there often are latent controls additional to any ill-defined interface spec. (1/3)
Steve
CC BY-SA 4.0
2024-09-17T13:33:45.677Z
I can't be sure what software you write and therefore how you have no execution time constraints, but if you are an industrial developer then woe betide your employer's financial health whilst you wait 6 months, with the computer sitting on UPS, for each simple call to return. I'm more inclined to think you're wilfully misrepresenting your situation as requiring *no* guarantees on performance, and even so, it just shows once again how out of touch your context must be from the normal context of software design. (2/3)
Steve
CC BY-SA 4.0
2024-09-17T13:40:33.227Z
The reason why *"anyone’s failure to consider that "fast X" isn’t the same as "X" makes "X" ill-defined"*, is because I have established that execution time is an aspect of interface behaviour, and I have established the prevailing importance of that aspect of behaviour to software developers, and therefore the absence of a definition of that behaviour for an interface, means that interface is ill-defined. Cases where *improved performance* (reduced execution time) often matter, is when it leads to congestion of a shared resource. (3/3)
Steve
CC BY-SA 4.0
2024-09-17T13:57:14.487Z
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/155286/discussion-between-mistermiyagi-and-steve).
MisterMiyagi
CC BY-SA 4.0
2024-10-14T14:04:37.100Z
This doesn’t provide an example.
The Empty String Photographer
# Are there languages geared towards component-based design?
Posted by: username_0 on 2024-09-14
I kind of like the idea of interacting "black boxes" that have well-defined interfaces and hidden internal state.

Are there any programming languages that specifically encourage this sort of program design (I believe, the term is "Component-Based" or "Component-Oriented Programming")? I understand that you can do this in pretty much any languages, especially OOP-languages like Java or C# have all the tools available, but they typically come with a whole arsenal of other stuff and are multi-paradigm, so they just happen to support this paradigm as well.

Are there languages that are CBP/COP-first?
**Tags:** language-design language-comparison
> **Comments:**
> **username_1**: Is there a difference between component-based design and object oriented design?  
> **username_0**: In OOP you have inheritance, so you build a hierarchy of classes and you have to know how parent class operates in order to properly use it in your own class. In CBP you have interfaces and you combine things together instead of extending them. Imagine a Java class that is `final` and only has : 1) an interface in the form of `public` methods (no public access to fields!) 2) `private` fields that represent internal state, totally hidden from the "outside world" 3) maybe some `private` methods that serve as utility functions.  
> **username_2**: There are many OO languages without (classical) inheritance, and there are paradigms that incidentally enforce total encapsulation, like the actor model, or really any message-sending OOP; are those in scope, or is an explicit focus on component-orientation in the design what you're looking for (and if so, do  component-based systems avant la lettre like Oberon count too)? I can't speak much to the overall contents, but at the least [Peter Hans Fröhlich's PhD thesis](http://oberon2005.oberoncore.ru/paper/pf2003.pdf) ought to be very relevant, albeit twenty years old.  
> **username_2**: The short answer to the title question is definitely "yes", I'm just trying to suss out the boundaries here.  
> **username_0**: @MichaelHomer I'm sorry, I don't think I'm competent enough to be more specific, so I'd be interested to know more about the possible options :) Actor model and message-sending OOP, from what I know about them, both seem to fit my criteria. So if you could name a couple of languages that follow these paradigms... Basically, yes, I'm looking for languages that treat encapsulation, composability and separation of concerns as primary way to write code. Thanks!  
> **username_0**: Think of something like "microservice-architecture" but within a language.  
> **username_3**: Would the obvious example of [Modula-2](https://en.wikipedia.org/wiki/Modula-2) (and its predecessor [Mesa](https://en.wikipedia.org/wiki/Mesa_(programming_language)) and successors [Modula-3](https://en.wikipedia.org/wiki/Modula-3), [Oberon](https://en.wikipedia.org/wiki/Oberon_(programming_language)), &c) count?  That pre-dates widespread OO support, but is strongly aimed at modular programming.  
> **username_4**: I agree with Michael Homer that this sounds quite like the actor model, and also "message-passing" OOP (minus inheritance). If the reason you exclude languages like Java is because are multi-paradigm, then some of the older "pure OO" languages are probably still in bounds.  
> **username_5**: Perhaps I'm missing something - but [Rust](https://www.rust-lang.org/) strikes me as the canonical popular example here. You define `trait` interfaces and explicitly `impl` them on types. These function by composition and in stark contrast to inheritance. Quite a lot of thought has been given to having well-defined "coherent" interfaces and such, though I would imagine less than some other more focused languages.  
> **username_4**: @apropos Rust doesn't really "encourage" you to use traits, nor to encapsulate type members.  
> **username_6**: Isn't this what the Ada designers envisioned? The goal was to be able to have teams of programmers where the users of a module were just given the input/output specs, and the implementors were given the contract.  
> **username_5**: @kaya3 late responding to this, but I'd somewhat disagree: functions not being accessible out of their module by default, structs needing `pub` indicators per-field, and there being no way to express code that is generic over the *behavior* of a type w/o traits (think a `<T>` that expresses that *some* functions are available on `T`) all strike me as encouraging the use of traits and encapsulation.  
> **username_5**: Though I think I would also argue that Standard ML is a valid answer to this question, so take that as you will :-)  
> **username_7**: As the answers show, you need to describe what you mean by a component. I've seen a book entitled 'Component-based software design in C# and Java' that just assumed components are objects and didn't mention components at all. A C# component is more or less a Java Bean and they are much more than just an object. Is that the notion of component you're referring to?  
---
## 6 answers
### Answer by username_2 on 2024-09-16. Score: 7
This question is somewhat asking two different things:

* are there languages aimed at supporting component-oriented programming;
* and are there languages with certain modular encapsulation properties

The answer to both questions is yes, but I think the idea that either implies the other is mistaken. [Eric Lippert has pointed out that](https://langdev.stackexchange.com/a/4066/133) C♯ was explicitly geared towards component-based design... but you've already ruled that out as an instance of what you're asking about! We will find both languages that aim to support component-based design and those that have the combination of (absences of) features you're looking for. I also have a couple of notes about languages that are geared towards components *by* building around the sorts of features you want to avoid.

---

In the comments you refined the details of what you intended a bit further:

> In OOP you have inheritance, so you build a hierarchy of classes and you have to know how parent class operates in order to properly use it in your own class. In CBP you have interfaces and you combine things together instead of extending them.

There are plenty of object-oriented languages that don't have (classical) inheritance, so we can look to those. I'd even argue that "in OOP you have inheritance [and] classes" is false in itself.

For example, [prototype-based languages](https://en.wikipedia.org/wiki/Prototype-based_programming) do not inherently require privileged access to a parent in their inheritance model — in fact, it tends to be a more obvious issue to provide that in them, leading to the "vampire problem" (although many do anyway, because it's either helpful or desired by users). Without privileged access, these parent pointers amount to assistance using the public interface of another object to "favour composition over inheritance".

You went on further with:

> Imagine a Java class that is final and only has : 1) an interface in the form of public methods (no public access to fields!) 2) private fields that represent internal state, totally hidden from the "outside world" 3) maybe some private methods that serve as utility functions.

There are also plenty of object-based languages and programming models that have this sort of hard encapsulation boundary. In particular, it is very common in languages designed with distributed systems in mind, but it's also a pure realisation of the message-passing model of object orientation.

A fairly clean example of all this is the [E language](http://erights.org/). Objects in E are conceptually isolated and entirely self-contained. "Fields" are lexically-captured variables, invisible through an object reference. It has no inheritance, instead supporting what it calls "delegation" to the *public* interface of other objects as ordinary method calls (the form [Jones et al. identified as "forwarding"](https://doi.org/10.4230/LIPIcs.ECOOP.2016.13), to contrast with JavaScript-style "delegation" that preserves identity; preserving identity enables downcalls, which *can* couple parent and child more closely). Each object can then be treated as a component, its public interface defining exactly what can be done with it by clients. [Emerald](https://www.emeraldprogramminglanguage.org/authorsVersion.pdf) was an earlier distributed language with similarly-strong object-level encapsulation, no classes, and no inheritance, which influenced a lot of subsequent work.

The [Actor model](https://en.wikipedia.org/wiki/Actor_model) in general tends to have this property: there is no communication between objects but messages sent to the receiver's inbox, so the public interface is the only access to the object and covers all the functionality it can provide. Some actor systems have classical inheritance, and so might fall foul of the first criterion, but many don't.

There are also non-distributed languages that start from the same point, and it's not especially uncommon. Message-passing OO is one of the primordial forms of object orientation, so there have been many instantiations of it and often without classical inheritance. In these systems an object *is* an identity that can receive messages and decide what to do in response to them. The only form of interaction between different pieces of code is such a message send, so no other leaks can occur. The public interface is the set of messages that an object plans to understand, and there's no access to the implementation beyond that.

---

Outside of object systems, languages like Wirth's Modula-2 provide strong encapsulation at the module level. Nothing from inside a module is available from the outside unless explicitly exported (and explicitly imported on the other end). Any module defines a self-contained component from the perspective of other code; it is possible to choose to export a mutable field, which may not meet your requirements here, but it is always an explicit decision. Its follow-up Oberon added more OO facilities and gets closer to the conceptual COP model, before the name was coined. An explicitly component-based spinoff by way of Oberon was [Component Pascal](https://blackboxframework.org/index.php?cID=home,en-us).

Many language families have strongly-encapsulated modules, including ML, which seem like they provide for component-based design just as much as the object-based systems do. It's not often talked about this way, but Haskell would tick off all of your listed boxes for a component-based language. This may be a sign that the terminology is still under-defined here, because I don't think these sorts of language are really what you were thinking of.

---

There are some specifically component-oriented language designs that probably meet all your requirements, or at least raise questions about tweaking them. [Peter Hans Fröhlich's PhD thesis is titled [Component-Oriented Programming Languages: Why, What, and How](http://oberon2005.oberoncore.ru/paper/pf2003.pdf) and he makes some similar points to you here. As part of it, he designs a language called Lag*oo*na, which draws together all of the points above from other languages. The thesis is pretty accessible and worth a read if you're interested in this area, and chapter 5 sets out the language design.

[Exil](https://doi.org/10.1145/2166929.2166932) is a Smalltalk-based component-oriented design, with perhaps not quite as much heft behind it but a more explicit component design with explicit inter-component message ports. This is lifting one style of component design into the language level, but it's possibly not the one you're looking for.

There are a number of others of greater or lesser significance, although not many that made it to the mainstream.

---

There is also a relationship here to the "[Lego hypothesis](https://doi.org/10.1145/1060710.1060716)", that software can be assembled out of many small predefined components, which goes back in different terms at least to [McIlroy's "Mass produced software components"](https://www.cs.dartmouth.edu/%7Edoug/components.txt) in 1969. This has been an aspiration and a goal for many people and many language design projects; I don't think any claim to have accomplished it, and I'm not sure anybody truly believes in the strong version of it (it's empirically false in existing languages). However, there are many languages that try to get closer to the ideal of component-based program construction, and many more that incidentally provide what you're looking for without necessarily having that label on it.

As well as those points, there are different conceptions of "component" that lead to different results. Something like [gbeta](https://tidsskrift.dk/daimipb/article/view/7654/6510) could be said to be designed for the creation of well-designed, separable, safely interacting components — but it's *very* heavily built around inheritance as a construct! I think equating broad features, or their absence, with component-based design is probably an error, and it's better to talk specifically about what we're actually looking for rather than lumping different pieces together, because we'll all have slightly different ideas of what that means.
---
### Answer by username_8 on 2024-09-14. Score: 4
> Are there any programming languages that specifically encourage this sort of program design (I believe, the term is "Component-Based" or "Component-Oriented Programming")?

Yes. The second paragraph of the C# 1.0 specification is

> C# is an object-oriented language, but C# further includes support for
> component-oriented programming. Contemporary software design
> increasingly relies on software components in the form of
> self-contained and self-describing packages of functionality. Key to
> such components is that they present a programming model with
> properties, methods, and events; they have attributes that provide
> declarative information about the component; and they incorporate
> their own documentation. C# provides language constructs to directly
> support these concepts, making C# a very natural language in which to
> create and use software components.

---

> OOP-languages like Java or C# have all the tools available, but they typically come with a whole arsenal of other stuff and are multi-paradigm, so they just happen to support this paradigm as well. Are there languages that are CBP/COP-first?

As the spec clearly says on the first page, C# 1.0 was designed from the ground up to create and use components: packaged-up functionality with clear interfaces, that can be versioned over time and describe themselves. C# is a component-first language, by design.

That whole "arsenal of other paradigms" -- generic typing, null safety, query comprehensions, dynamic dispatch, and so on -- got added later.

---

I'll take this opportunity to note also that the things which make languages suitable for component-oriented software design are often not actually *language* features per se. The entire .NET *framework* that underlies C# was designed to be component-oriented. Having such a strong bias from the framework has both advantages and challenges for the language designer.
---
### Answer by username_9 on 2024-10-26. Score: 1
I am surprised that no one has mentioned the ML family of languages and their extremely expressive module system, which gives you powerful ability to encapsulate and abstract components. Especially, OCaml provides further extensions such as applicative functors, recursive modules and first-class modules that make the module system even more powerful.
In ML, a module contains data (including functions) and types, and a signature is a specification (or contract) for a module. For example, in OCaml one might write:
module type Stack = 
  sig
    type 'a stack
    val empty : 'a stack
    val push : 'a -> 'a stack -> 'a stack
    val pop : 'a stack -> ('a * 'a stack) option
  end

as the specification for a stack. Then, one might implement a stack in many ways, for example as a list:
module List_Stack : Stack =
  struct
    type 'a stack = 'a list
    let empty = []
    let push a s = a::s
    let pop s = 
      match s with [] -> None | t:l -> (t, l)
  end

Note that this is just but one implementation of Stack. Whenever a stack is needed, any valid implementation of the Stack signature (i.e. interface) can be used.
Furthermore, ML modules are compositional, and this is where ML really shines. Which means that one can write functors which are modules that take other modules as arguments. For example, a generic hash map that takes any hashable type as key:
module type Hashable =
  sig
    type t
    val hash : t -> int
  end

module type HashMap = 
  functor (Key : Hashable) ->
    sig
      type key = Key.t
      type 'a map
      type add : key -> 'a -> 'a map -> 'a map
      type lookup : key -> 'a map -> a
    end

This lets you reuse and compose components at will, and to plugin different implementations of the same components easily.
These are the basics of a ML-style module system. OCaml also support some extensions to this system, making its module system extra powerful:

recursive modules, which allow for cyclic and mutual dependencies between components;
first-class modules, which allow one to write functions that take modules as arguments or return modules, so that a programmer could select an implementation between multiple valid implementations at runtime based on input.

Overall, ML modules are an extremely powerful tool for component-based design, and can express modular designs impossible in other programming paradigms. However, as far as I know, only two ML family languages, Standard ML and OCaml, have full-fledged ML-style module systems.
---
### Answer by username_10 on 2024-10-06. Score: 1
The usual term for “black boxes that have well-defined interfaces and hidden internal state” is **[modules](https://en.wikipedia.org/wiki/Modular_programming)**. The first language that codified modules was [CLU](https://en.wikipedia.org/wiki/CLU_(programming_language)). CLU was never industrially successful, but it established many interesting concepts. Barbara Liskov's *[A History of CLU](https://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-561.pdf)* is worth a read (also *A Note on CLU* by Liskov 1975 and *Abstraction mechanisms in CLU* by Liskov et al in Commun. ACM 1977). After CLU, the main driver for module systems and abstract types in programming languages is ML (both in Standard ML and Caml strands).

If you want to look at a language with a module system and not a lot of other sophistication in its type system (in particular no objects or classes), look at [Standard ML](https://en.wikipedia.org/wiki/Standard_ML).
---
### Answer by username_11 on 2024-10-17. Score: 0
You could argue that UML fulfills the requirements. UML has a number of design functions which can be expressed in a graphic language, as well as a in more traditional type of text language. UML defines a one-to-one translation between the text version and the graphical version.

There are translators that can translate to and from traditional programming languages, at least in some problem domains. In theory you could program a full system using only UML, although I believe it is seldom done.

The different diagrams in UML basically falls into two categories: structure and behavior.

The structure diagrams (either as graphical diagrams or as text descriptions) can describe things like (there are a few more):

* classes (translates directly to classes in OOP programming languages)
* objects (actual instances, most often of classes)
* packages (how code parts are packaged together, as example into and application or a supporting library)
* deployment (how code is deployed when several computers are used).

The behavior diagrams (as well as their text versions) describe things like:

* use cases (how things external to the system uses it)
* activities (how activities interact)
* state machine diagram (state machines are often used in certain domains)
* sequence (the sequence between different actions / happenings)
* timing

In real-world usage, UML seems to mostly used as a high-level design language. The design is then translated more or less manually into an actual programming language. But as managed there are tools that allow you to create source code directly from the diagrams. Given a set of rules the tools allow you to translate from actual source code inte UML for further refinement and later translated back to source.
---
### Answer by username_12 on 2024-09-14. Score: -7
> I kind of like the idea of interacting "black boxes" that have well-defined interfaces and hidden internal state.

I liked the idea of Santa Claus when I was a child too.

A "black box" *means* an ill-defined and poorly-understood thing, so you've already stated a contradiction and as such this answer is about to be a frame challenge.

I've never - *never* - in my life encountered a man-made machine where you know strictly what inputs it accepts and strictly what outputs can arise from those inputs (the "interface"), but somehow you don't know the part in between the input and output (the "internals").

In software, the reality is that there is no true separation between interfaces and internals. They are the mating parts of the implementation of the workings of a machine which a software developer designs.

A fully-defined interface always amounts to access to a reference implementation of the internals. Everything short of that just leads to the interface being less precisely defined than is possible with a reference implementation.

Many usages of interfaces tolerate some imprecision. Indeed, even half-wits are capable of writing programs that are correct sometimes, so imprecise use does not always lead to total failure, but to the workings of the machine being either degraded in quality or only accidentally correct.

A documented interface without documented internals, typically defines some things loosely or not at all.

For example, the processing time from call to return is typically defined loosely and implicitly, rather than in terms of exact clock cycles - although contempt (or ignorance) of execution delay as a genuinely measurable output of an interface, is something that regularly penalises bad cryptographers.

But this imprecision in the description of the interface is a source of complexity, error, and unpredictability, not something to be desired for its own sake.

Imprecision often has to be accepted when no one developer can understand every detail of the entire workings of a very complicated machine. The challenge of good interface design then, is to design interfaces in ways that the imprecision relates only to matters which are irrelevant to the client of the interface.

That is, the designer of the interface needs to have an idea of what aspects of the internals behind the interface concern crucial behaviour on which another developer must be able to rely, and what aspects are arbitrary and can be varied without damaging another's reliance.

This is completely the opposite of "black boxes" and "hidden internals". It requires clear glass boxes whose contents are reasonably obvious. It requires developers who are still somewhat involved in each others' work and working from a somewhat shared understanding.
> **Comments:**
> **username_8** (2024-09-14): The question asked for examples of languages that meet a certain design criterion. This answer makes no attempt to answer the question that was asked, but instead goes off on a rant about how a thing that the original poster enjoys is actually bad.  
> **username_13** (2024-09-15): Sorry, I see plenty of times where an interface is plenty without knowing details of how it's implemented. UI controls for example. It obeys the spec as to how it's created, how it's initialized, when it redraws. I, as a programmer, do not need any knowledge at all of how it is implemented. Depending on what I am writing, I might not even need knowledge of how it presents to the user.  
> **username_12** (2024-09-15): @EricLippert, I deny that "black boxes with *well-defined* interfaces" exist. Rather, the blacker the box, the more loosely or ill-defined the real interface. Often with these things, the concept of the "interface" itself is defined in an artificially narrow way to consist only of the data types of the members, arguments, or results - I mention the example of *execution time* of a call which is rarely considered part of the explicit interface in these discourses, but is always somewhat relevant (and extremely relevant in cryptography). (1/2)  
> **username_12** (2024-09-15): Nobody says one interface where you wait a second for results, another where you wait a week, and a third where there is the possibility of no return at all, are all the "same interface", just because the method signatures say they all take an int and return an int, because profile of behaviour in the round is completely different. (2/2)  
> **username_12** (2024-09-15): @SoronelHaetir, that's not my point. As I say, many usages of interfaces tolerate sloppiness - and the world is rife with crap, buggy, flawed software. I often use interfaces of complex software whose internals I don't remotely understand - often, there's a small space of behaviour which from experience I know works for my purpose, and hope will remain consistent into the indefinite future. But they're not thereby "well-defined" - they're an ill-defined thing which I merely hope someone else has designed intelligently to anticipate my usage and behave sensibly in relation to my usage.  
> **username_2** (2024-09-15): This might be a fine answer to a question about component-oriented programming on a *different* site (Software Engineering?), but it doesn't have anything to do with *this* site's topic. If it concluded with "therefore no such languages exist" then it would, strictly, be an answer to this question, but it presently doesn't even go that far.  
> **username_12** (2024-09-15): @MichaelHomer, it must have something to do with this site's topic if a person, to introduce their question, alleges the existence of something I'm saying doesn't exist and is a contradiction in terms (for reasons that can't be summarised in a comment). I realise the OP was not asking about the issue I've raised, presumably because they assumed it was an uncontroversial starting point, but this answer is addressing that flaw in their premise. I'm less inclined to say that "no such languages exist" - rather, that languages do exist which facilitate the OP's faulty thinking about interfaces.  
> **username_14** (2024-09-15): This answer seems hung up on an overly restrictive definition. There are tons of abstract things out there that are still well defined but have no single, concrete reference implementation. Do iterators not exist as a well defined thing? Are sets ill-defined because their order is not defined? Just because an interface does not specify every inconsequential detail doesn’t make it imprecise, just abstract. People don’t need "abstract" to write bad, sloppy code and there are many useful, good abstractions.  
> **username_12** (2024-09-15): @MisterMiyagi, my argument is not that every internal detail always counts in every case. My argument is that every detail always counts in some case. Or speaking even more precisely on the point, that there are no general class of details, which would be important to know of or discuss amongst ourselves as a general class, which never count in any case. Software developers have to make informed decisions in the context about what counts and what doesn't. (1/3)  
> **username_12** (2024-09-15): My argument is also that there are a large class of details which are not in fact free to be varied arbitrarily, but have acceptable ranges of behaviour, even if it can be easily shown that no one specific behaviour is always required. These constraints are themselves usually ill-defined and usually implicit, but are certainly there. I gave the example of execution time - it is rarely constrained to an exact number of clock cycles, but there is usually a range of acceptability, and the actual execution time is determined by the internals. (2/3)  
> **username_12** (2024-09-15): Also my argument is not against using abstractions. It is against people becoming so familiar and ensconced with these abstractions, that they forget there is a wider reality where these abstractions do not properly apply, or that there are important aspects of very routine problems which they do not cover. The consequence appears to be that they lose (or do not even acquire) the knowledge and skill to make an informed decision in the first place about what matters and situations the abstractions do and do not properly apply to. (3/3)  
> **username_8** (2024-09-15): This sounds like a great blog post; it's not an answer to the question that was asked, and so doesn't belong here.  
> **username_4** (2024-09-16): *"I've never - never - in my life encountered a man-made machine where you know strictly what inputs it accepts and strictly what outputs can arise from those inputs (the "interface"), but somehow you don't know the part in between the input and output (the "internals")."* ─ Have you never used `Array.prototype.sort` in JavaScript, then? Sure, you can go and read about how it's implemented in various JS engines, but you don't have to in order to use it, and if you are programming for the web then you really *don't* know in advance which implementation will be in use.  
> **username_12** (2024-09-16): @kaya3, but it's possible to use things you don't properly understand, and which are ill-defined. The mere use of things doesn't thereby establish that they must be well-defined. And definition is not a binary state, but a matter of precision. Lots seems to be made of the fact that internals behind the interface can be varied - but that latitude exists often as much because the interface is *not* well-defined, rather than because it is well-defined. That's typically why viruses have been introduced into open source libraries - everyone keeps pretending the interfaces are well-defined.  
> **username_14** (2024-09-16): @Steve I don’t think anyone here is trying to deny interfaces are defined and used badly at times. Rather the issue is the *categorial* statement in the answer that by leaving *any* detail undefined an interface is *inherently* not well-defined.  
> **username_4** (2024-09-16): If your opinion is that `Array.prototype.sort` is ill-defined, then you should make a comment to the TC39 that you have found a mistake or omission in [its specification](https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.sort).  
> **username_12** (2024-09-16): @MisterMiyagi, I am tending towards that position, yes, that leaving details undefined means the details are not well-defined.  
> **username_12** (2024-09-16): @kaya3, well I've already repeatedly mentioned latency and execution time as an often-overlooked aspect of interface behaviour, and I see no mention of that in your specification (although I'm prepared to be corrected, since I am not familiar with that long document). To give you an idea where this regularly counts for practical software design, it's when calls are local versus those being remoted over a network connection.  
> **username_14** (2024-09-16): @Steve That seems infeasible. You *cannot* define everything completely - in the end how something actually behaves will depend on the compiler, the dependencies, the OS, the arch, possibly the make and build of the hardware (yes, we got hit by that in practice). Saying that a concrete *code* implementation is well-defined is just picking an arbitrary level. The entire point of programming languages is to make abstractions and those will never be defined down to every detail.  
> **username_4** (2024-09-16): You said: *"I've never - never - in my life encountered a man-made machine where you know **strictly what inputs it accepts and strictly what outputs can arise** ..."* (emphasis mine). Latency and execution time do not affect what inputs it accepts or what outputs can arise, so this doesn't fall under your claim. Nonetheless, the specification of `Array.prototype.sort` *correctly* doesn't promise anything about how long it will take, because that genuinely *isn't* known in advance.  
> **username_4** (2024-09-16): If you want to say that means the behaviour is uncertain then fine, but "uncertain" does not mean "ill-defined". It just means that the latency or execution time is not part of the specified behaviour and can't be strictly relied on by the programmer. In the same way that iteration order of a hash table is not part of its specified behaviour and can't be strictly relied on. Something can only be reasonably called "ill-defined" if its purported definition is unfit for purpose.  
> **username_12** (2024-09-16): @MisterMiyagi, I'm not arguing that this stops at the code internals  I agree the hardware itself can come into it, so can physics. However I'm not sure your tone suggests you're about to integrate this realisation you've made that nothing is well-defined, and therefore champion my argument against the contradiction of "black boxes with well-defined interfaces". I'm not suggesting interfaces need to be well-defined - you're setting that standard for yourself, which I think is unattainable.  
> **username_12** (2024-09-16): @kaya3, but execution time *is* a measurable output. You're lawyering with me now, suggesting that this output isn't one that meets your criteria of an output, when my case is precisely that this lawyering is self-deceptive and self-indulgent, and fails to engage with bread and butter realities of software design, such as that *performance always matters*, and the only question is *how much* it matters. Nobody makes an interface call just to have the computer whirr away for a thousand years. (1/2)  
> **username_12** (2024-09-16): I agree that it is only reasonable to call something ill-defined if the definition is unfit for purpose. And I'm saying black box interfaces in general are unfit for the everyday purpose of practitioners writing correct and reliable software. Moreover, it is equally unfit for theorists to keep talking amongst themselves about "well-defined interfaces", because such language encourages you to habitually ignore (or treat as nugatory) all the ill-defined parts of interface behaviour which are actually of central importance for real practitioners when they design software or use interfaces. (2/2)  
> **username_14** (2024-09-16): @Steve I don’t think that something must be completely defined to be well-defined. As mentioned before I do consider abstract things perfectly well-defined. If you think the two *must* be equivalent, it’s probably more productive to agree to disagree.  
> **username_12** (2024-09-17): @MisterMiyagiz I too don't think something must be completely defined to be well-defined. I just think all the *important* things have to be defined for something to be well-defined.  
> **username_14** (2024-09-17): @Steve Well clearly we disagree on what is important then. Sure one might care for things like speed *overall*, I.e. when choosing concrete components, but most *individual* pieces don’t have to prematurely enforce that they only work with fast black boxes - and yes, we got bitten by misguided performance requirements in practice too. Tacking something like performance onto the concept of "sorted array" is wrong. Sure one might need something that is both fast and sorted at times, but it does not make the concept of just sorted ill defined.  
> **username_12** (2024-09-17): @MisterMiyagi, I'm just giving execution time as an example to demonstrate my *point* which is that you *systematically* ignore things about the behaviour of implementations which are considered generally important to software design in practice, and you react stubbornly and defensively when it is pointed out how simplistic and unreal are the tenets you are proceeding from. I'm not seeking advice about when or to what degree performance is important - those are questions which I would decide in the context of a specific application. I'm simply pointing out your emperor is wearing no clothes.  
> **username_14** (2024-09-17): @Steve Ignoring parts is the whole point of abstraction. You don’t have to point it out, it’s literally what the word means. Likewise for black box and interface. To make a decision in the context of a specific application or even environment, not an isolated piece of code, is exactly what these concepts are there for.  The emperor doesn’t wear any clothes because he didn’t dress yet, not because he didn’t notice the breeze.  
> **username_12** (2024-09-17): @MisterMiyagi, I think I responded to a previous iteration of your comment above. I haven't specifically said the concept of a "sorted array" is ill-defined. I'm talking about the approach generally of separating programs into "interfaces and internals", and whether interfaces which *conceal* the internals (or where implementors reserve the right to vary the internals "freely") can ever be "well-defined" interfaces. In my view, the interface of a *method* which sorts an array is ill-defined in an important and everyday respect, if there is no constraint on execution time.  
> **username_12** (2024-09-17): @MisterMiyagi, the point of designing abstractions is to ignore the parts of a problem which are *unimportant* in practice, whilst bringing narrower focus onto what is important. My position here is that you are systemically ignoring the *important* parts of software development too - that you are abstracting in an incompetent and out-of-touch way, which causes your own confusion and leads you to a proliferation of absurd claims that are inapplicable to the reality of how software is designed. (1/2)  
> **username_12** (2024-09-17): The organisation of code into interfaces and internals (which is a very standard practice amongst developers, regardless of the language in use) does not require the internals to be concealed from anybody and a "black box" produced, it does not require that the interface standing in isolation be wholly "well-defined", and it does not require that the internals behind the interface should be variable "freely". There is no "abstraction" that requires these claims to be made - claims which don't correspond to the interfaces of any real software. (2/2)  
> **username_14** (2024-09-17): @Steve I really have no idea what makes you think you are in a position to say what I (or perhaps people like me) are systematically ignoring or are incompetent about or out of touch. It’s a reality that much code is more general than any specific program and only applies to abstract requirements. Every library targeting "iterators", or "awaitables" or one of the many, many useful abstractions out there is written without a concrete implementation of that black box that one could peek into. This has nothing to do with concealing things and is very much part of real software.  
> **username_14** (2024-09-17): That you have *specific* problems with *specific* cases does not make the concepts or the people using them bad by itself. I haven’t encountered any notable concept, paradigm or language that no one used badly.  
> **username_12** (2024-09-17): @MisterMiyagi, my issue isn't whether all these "useful abstractions" exist - it's whether their interfaces (taken standalone) are well-defined or not. I've already been quite clear that developers are quite capable of using *ill-defined* things - I write ill-defined interfaces all the time, and I often vary their implicit behaviour subsequently too - so the mere use of interfaces does not establish that they must be well-defined. If standalone interfaces were only very rarely ill-defined, I might cede the point, but on the contrary I think ill-definition is the rule.  
> **username_14** (2024-09-17): @Steve Then we are back at square one at which I have no idea what criteria you apply for well- or ill-defined. Or for that matter why you go the extra mile to declare every black box ill-defined per se, or some of the other categorical claims.  
> **username_12** (2024-09-17): @MisterMiyagi, I'm applying the same criteria as you do - an interface is well-defined when the internals can be a black box, varied freely by the author, and nobody using the defined interface would care about the obscurity of the internals or have reasonable cause to object to any variation in the internals. I use execution time as an example with wide applicability, where it is very rarely a defined part of the interface behaviour, but clients of the interface would often object to a radical degradation in speed, and in some cases they would even object to an increase in speed.  
> **username_14** (2024-09-17): @Steve And I don’t get the performance example at all. Most client code should not care about performance. The application as a whole *maybe* yes (but I have counterexamples of this being premature too) but that is not the concern of individual pieces. Most code components will work fine with slow and with fast black boxes; that  some concrete configuration of all those components and boxes has additional criteria (say, performance) does not mean that every component using an interface has to care about those criteria as well, and that not caring about them means that piece is ill-defined.  
> **username_12** (2024-09-17): @MisterMiyagi, I say with supreme confidence that the speed of execution is a generally important consideration that regularly factors in how interfaces are structured and used within software designs. Often this begins with the rules of thumb of experienced designers, such as using network calls in a non-chatty way, and designing interfaces in a way that doesn't require chattiness. I don't know what you mean by "premature". The argument I'm making is that performance profiles are rarely defined, making a standalone interface without definition of such an important matter ill-defined. (1/2)  
> **username_12** (2024-09-17): The fact that many interfaces "work" with slow or fast internals (in some conventionally reasonable range) is not the question here. The question is whether there is any *definition* or not of the execution time of the interface. You seem to be arguing that interfaces are "well-defined" because you have a right to ignore all the important things and everyday concerns of software developers which, if acknowledged, show that what you deem well-defined is in fact ill-defined. In other words, you define things "well" not by constraining behaviours, but by ignoring more and more things. (2/2)  
> **username_14** (2024-09-17): @Steve I say interfaces are well-defined if they cover everything an implementation must provide. That’s it. An interface *may* include performance beneficial things like bulk calls or complexity guarantees, but it doesn’t have to. There are tons of interfaces for which performance is not essential and omitting it doesn’t make the interface ill-defined. Ignoring something in an interface also does not mean that a *concrete implementation used in a concrete application* shouldn’t provide it if the larger usecase does require it - it only means the interface isn’t the place to define it.  
> **username_14** (2024-09-17): I also say with supreme confidence that adding a definition of performance to every or even most interfaces is premature optimisation. Many individual pieces of a software have no idea about the performance requirements of the whole thing and thus shouldn’t constraint it.  
> **username_12** (2024-09-17): @MisterMiyagi, no, there is *no* case where performance is a completely irrelevant matter for software developers. People run computers to get results, not to die waiting. I'm not arguing that maximum performance is always necessary - I'm arguing that a specification of interface performance is necessary for the interface to be "well-defined", because performance is an aspect of the behaviour of an implementation (which consists of an interface and internals), and that aspect of behaviour is one that is always important for a designer of software to consider. (1/2)  
> **username_12** (2024-09-17): I'm not suggesting you should add a performance specification to every interface. I'm suggesting you should accept that standalone interfaces are never well-defined - the assertion in my answer which I am defending. I have adduced the example of execution time, as something that is undoubtedly missing from almost all interface definitions. If you don't know the performance requirement of my application which uses your black box, then how dare you vary its performance? (2/2)  
> **username_14** (2024-09-17): If you require guarantees about performance, why are you using interfaces that don’t actually give those guarantees? Sorry, this whole situation feels like blaming mechanisms and others for - how did you put it? - that you are abstracting in an incompetent and out-of-touch way.  
> **username_14** (2024-09-17): Indeed most of my code does not require any performance guarantees and subsequently interfaces without them are perfectly well-defined. The ones that do require such guarantees also request them. I don’t see why anyone’s failure to consider that "fast X" isn’t the same as "X" makes "X" ill-defined.  
> **username_12** (2024-09-17): @MisterMiyagi, because I have to rely on large libraries of code or complicated technologies written by the world's other developers, and so I use them anyway in their ill-defined condition and with their behaviours which I ill-understand, to put it bluntly. That said, the intelligence and consideration of other developers, the culture and experience I broadly share with them, and the desire of vendors to make profits, means that there often are latent controls additional to any ill-defined interface spec. (1/3)  
> **username_12** (2024-09-17): I can't be sure what software you write and therefore how you have no execution time constraints, but if you are an industrial developer then woe betide your employer's financial health whilst you wait 6 months, with the computer sitting on UPS, for each simple call to return. I'm more inclined to think you're wilfully misrepresenting your situation as requiring *no* guarantees on performance, and even so, it just shows once again how out of touch your context must be from the normal context of software design. (2/3)  
> **username_12** (2024-09-17): The reason why *"anyone’s failure to consider that "fast X" isn’t the same as "X" makes "X" ill-defined"*, is because I have established that execution time is an aspect of interface behaviour, and I have established the prevailing importance of that aspect of behaviour to software developers, and therefore the absence of a definition of that behaviour for an interface, means that interface is ill-defined. Cases where *improved performance* (reduced execution time) often matter, is when it leads to congestion of a shared resource. (3/3)  
> **username_14** (2024-09-17): Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/155286/discussion-between-mistermiyagi-and-steve).  
> **username_15** (2024-10-14): This doesn’t provide an example.  
---
