5

As described here, a function can be said to be a query when it returns a value, and a command when it modifies a value. It also states that a function should not be both.

That a query should not be a command seems popularly enforced by functional programming, in that it is a pure function.

Does a language exist, where if and only if the function is non-void, it cannot change state?

  • Trying to understand what you're asking. When state is immutable, nothing can change state (only create new state). Are you looking for some language outside of functional programming? – Erik Eidt Jan 2 '18 at 15:39
  • 2
    Command-Query separation is an architectural style, not a language element, and an optional one at that. – Robert Harvey Jan 2 '18 at 17:01
  • 1
    "That a query should not be a command seems popularly enforced by functional programming, in that it is a pure function.": A query is not necessarily a pure (referentially transparent) function, since it can access a file, get data from a server, and so on. So, even if the function does not change the state of the system, it can produce different results at different times because the state of the system has changed between different executions of the query. Therefore I would not say that pure functions in functional languages can be used to enforce command-query separation. – Giorgio Jan 2 '18 at 17:40
  • It's not a "language", so I'll just comment instead of answer, but Akka (in Java) or Akka.NET (C# / F#) uses an actor model that I think complements CQRS. All actors are unaware of any other actor's state, and all actions are carried in immutable 'messages.' Individual actors are responsible for choosing whether to interpret a message as a command or a query. – RJB Jan 4 '18 at 19:24
  • @RJB: But Akka does not enforce CQRS, as you yourself pointed out. – Robert Harvey Jan 4 '18 at 20:23
8

Yes, SQL has distinct commands for querys (reads) and commands (updates).

SQL has different commands for DML (Data Manipulation Language) for performing INSERT, UPDATE, DELETE.

For reads, use DQL (Data Query Language) for performing SELECTs (reads).

Languages like C# are OO based. The best you can do with a language like C# is to put up guardrails.

For example a query interface:

public interface IQuery<in TIn, out TOut>
{
    TOut Execute(TIn queryInput);
}

A command interface:

public interface ICommand<in TIn>
{
    void Execute(TIn commandInput);
}

One can also make object(s) immutable to ensure that they can not be changed once instantiated.

But, developers can ignore the guardrails so if Command-Query is being implemented in a language like C#, probably new code that is added should be code reviewed to ensure the pattern is being followed as initially designed.

  • Of course, why didn't I think of SQL? Is the reason no such OO language exist technical? Would it not be possible to create a Visual Studio extension that reflectively looked for violations, and reported them as warnings? – Chris Wohlert Jan 2 '18 at 18:42
  • 1
    Why would you want to? – Robert Harvey Jan 2 '18 at 19:39
  • Yeah, AFAIK, there's nothing stopping anyone from creating an OO language with such limitations. You'd basically just have to have a way to mark functions as "command" or "query" and then limit operations inside each based on the type. But then to do anything useful, of course, you need a construct beyond functions. After all, you can't run commands from a query, cause then the query isn't just a query. While SQL has separate queries vs commands, they do get mixed in actual SQL code often. Or at least callers would use both, typically. It's not very useful to be read only (or write only). – Kat Jan 2 '18 at 19:55
  • @RobertHarvey At this point I am just curious. I would also like to make it more evident to myself, so that I can more easily determine when it makes sense to follow and when not to. At the moment, I sometimes think of it and sometimes not, so it is really just to see how it would affect my work to be enforced by it. – Chris Wohlert Jan 2 '18 at 20:23
  • 5
    The main problem with this is that purity analysis, i.e. figuring out whether something has a side-effect (is a command) or not (is a query) is equivalent to solving the Halting Problem. SQL "solves" the problem by having three separate languages, DDL, DML, and DQL, and syntactically and semantically restricting them to only be able to do one or the other. It is not clear whether something like this would work for a general-purpose language. E.g. Pascal and its successors (Modula-2, Oberon, Component Pascal) distinguish between functions and procedures, but functions can still have effects. – Jörg W Mittag Jan 3 '18 at 7:43
-3

As far as I know there isn’t such a language because in some instances there are specific cases where you do need to both modify a value and return a value at the same time.

For example, in c# there is a common pattern used called TryGet. In this case you output a modified value of some parameter using the “out” keyword, while returning a bool to store whether the modification was successful.

So something like this simple example. (Typed on phone so sorry if there are errors)

bool TryGetFifthCharacter(string origString, out char fifthChar) {
    bool itWorked;
    if (length < 5) {
        ItWorked = false;
    }
    else {
        fifthChar = origString[5];
        itWorked = true;
    }
    return itWorked;
}

Use the function like this:

string orig = “hello”;
char fifth;
if (TryGetFifthCharacter(orig, out fifth)) {
    print(fifth);
}
else {
    print(“failed”);
}

So there are some cases where you want to do both things! Although I think this should be used only in very specific cases.

  • 2
    How does this answer the question? – JacquesB Jan 2 '18 at 16:48
  • Hmm I meant to say that there likely isn’t a language like that because sometimes you need to do both. I’ll edit my answer. Thanks. – Adam B Jan 2 '18 at 16:51
  • 3
    This pattern is only a workaround for the lack of multiple return values in C#. And the use of out does not modify a value, it assigns a value to a variable in the calling scope. – JacquesB Jan 2 '18 at 16:54

Not the answer you're looking for? Browse other questions tagged or ask your own question.