Data flow languages are close to my heart, I've implemented several, particularly in the context of data binding. They are a declarative way of describing a computation, and the computation can be analyzed to enable things like multi-threading, caching, incremental & lazy evaluation.
These properties come from the constructed data flow graph, which can be analyzed by an execution environment and potentially prepared by a compiler. They don't come from visual vs symbolic representation. They come from modelling a computation as data flow.
And yes, I have implicitly bundled the semantics with the syntax here. I suppose in doing so, I am arguing both that dataflow is a powerful and interesting way of modeling computations that allow for a lot of neat features and that visual representations are more natural and give additional useful benefits over text-based ones. I have not seen a compelling text-based dataflow representation, but that doesn't mean one doesn't or can't exist. LabVIEW actually compiles its block diagrams to what's known as DFIR, dataflow intermediate representation, which is then compiled to LLVM IR. The DFIR is helpfully visualized as a graph, although the dataflow graph is represented by text underneath.
I first learned to program FPGAs with LabVIEW. Now I am learning HDLs, and it's a bit painful. Understanding VHDL is not hard, but I find it to be a poor representation of what it is describing. The text-based representation hides the nature of the actual computation it's representing.
If you have any references to dataflow or any links to things you've done, I'd love to take a look. :)
I wrote a server-side framework for data entry AJAX apps in 2004-2006 time frame, canonical application was entering details for an insurance quote. The UI was data bound on the back end, and a minimal update over the wire could be calculated from the bindings.
The bindings were stored in an XML document pulled from a metadata server referenced by id from the session state, meaning that we could do live rollover of new versions. Previous pages with existing sessions would use the old logic, whereas new logins would use the new logic.
This gave rise to a number of nifty properties. The session state was serialized - in fact, it was never deserialized, it was a byte array that was traversed as various attributes were accessed and updated. If there was a bug, you could rehydrate the session state, and display all session variables etc. and evaluate the current value of all data bindings, meaning that you could figure out what the user was seeing on screen. A lot like Smalltalk or Lisp images, but much smaller, because the code was static and stored externally.
Everything from disable state on controls to tab order around the screen was controlled via data binding, dynamically updating in response to values entered. The UI logic was completely declarative.
The framework was called Topoix, there are fragmentary references to it on the interwebs. I wrote an HTTP server & debugger for it too.
The data binding language was called Gravity, structurally it was a subset of C# in .NET 2 era, but it was declarative because it was not merely executed, but analyzed for data flow purposes.
The experience of creating a language amongst other things lead me to Borland, where I worked on the Delphi compiler, and partook in initial design of the new version of the data binding for controls feature. I can't claim any credit or otherwise for it, I was focused on other things, like rich reflection, which in itself helps data binding work well with a native language.
More recently, amongst many, many other things, I designed the web side data binding approach for the company I'm currently at, Duco. We're gradually replacing it all with React now, but it was useful to make pages reactive and automatically updating in response to new data at a time when people were doing jQuery from their event handlers.
An interesting academic paper at the time for me was "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" by Meijer et al. He's a decent chap to follow if you're interested in that seam: https://www.researchgate.net/profile/Erik_Meijer
I picked up one of my favourite jargon terms from his usage, "bijective", e.g. with respect to lenses. In a data flow context this is reversible computation, a nice thing to have if you're doing data binding against an editable control (rather than something like a label). Not only does the value you're binding to change in response to upstream changes in the model, but edits to the value can be propagated back to the model. Bijective is the technical term for a function which is mappable both ways, and lens is the CS term for the abstraction which encapsulates a data flow transforms required for a scenario like data binding.
These properties come from the constructed data flow graph, which can be analyzed by an execution environment and potentially prepared by a compiler. They don't come from visual vs symbolic representation. They come from modelling a computation as data flow.