Converting Imperative To Declarative

Based on discussion in CodeAvoidance, here are techniques for converting imperative algorithms into more declarative approaches, specifically the data-centric type. This is not the topic to discuss the merit of such conversions, just the techniques. IsDeclarativeLessExpressive would probably be better for value judgments. Nor should we battle over which kind of data structure to use here.

Nothing here appears declarative, merely data-driven.

Are you suggesting a title change? Before making the effort, let's explore the definition of "declarative" and compare it to "data driven".

And here I thought this page would be about PythoLogic? (http://lambda-the-ultimate.org/node/view/240), a framework for embedding PrologLanguage in PythonLanguage.

There are at least two kinds of "declarative":

Perhaps we should make the topic more specific? However, in a YagNi spirit, let's wait until we need a split.

[A useful operational definition of 'declarative' is that ordering and duplication of statements does not affect program behavior.]


Remove taxonomies from code

Convert any taxonomy to a data structure. For example, inheritance can be converted into a tree data structure.


Repeating use of parameters

Before:

  foo(a, b, c)
  foo(d, e, f)
  foo(g, h, i)
  ....
  bar(a, b, c)
  bar(d, e, f)
  bar(g, h, i)
After

  Begin Structure X
(1, a, b, c)
(2, d, e, f)
(3, g, h, i)
  End Structure
  funcLoopThruStructure(function=foo, dataSet=X)
  ....
  funcLoopThruStructure(function=bar, dataSet=X)


Convert simple look-ups into map structure look-ups

Before:

  select on locat
case 'HK': result = 'Hong Kong'
case 'NY': result = 'New York'
case 'LA': result = 'Los Angeles'
otherwise: result = 'Not Found'
  end select
After:

  Lisp-style:

(lookup ("HK" "Hong Kong") ("NY" "New York") ("LA" "Los Angeles") ("Not Found"))
which might be something like a case statement using symbols rather than strings as the key, depending on the values of the key's of course.

  (case key
('HK "Hong Kong")
('NY "New York")
('LA "Los Angeles")
(else "Not Found"))

Oracle Style:

decode(locat, 'HK', 'Hong Kong', 'NY', 'New York', 'LA', 'Los Angeles', 'Not Found')

Table Style

CityName = "Not Found" SEEK(Cities, CityAbbrev) IF FOUND() CityName = Cities.CityName ENDIF

Or

querySingleValue("select descript from cities where cityAbbrev='$cityAbbrev'", , "Not Found")
I actually made a utility function just like this once or twice. If nothing is found, it defaults to the second parameter. However, I could never decide how to handle multiple finds. One can have it use only the first record, raise an error, use the default, or have yet more parameters. What would you do?


Convert objects/classes with lots of attributes into data structures

Um, that's just silly, an object "is" a data structure, with its operations bound to it, what exactly would be the point?

Not all objects are "just" data structures. Objects connote rich operations, information hiding, abstract interfaces, getters and setters, et cetera. However, use of getters and setters (or attributes) for maintaining a lot of data tends toward ReinventingTheDatabaseInApplication.

The point here is to separate the semantic operations from the data management issues (such as concurrency, security, consistency, and persistence).

Moved some questions about "why" to IsDeclarativeLessExpressive.


Use Look-up Tables for MultipleDispatch

  Example Table Schema
  --------------
  factor_1
  factor_2
  factor_3
  factor_Etc....
  target
The "target" can be a rate, a code snippet or script name, etc. It could also have multiple targets that serve a role similar to methods in an OOP Strategy Pattern. To find the result, use WhereAndAnd query patterns.


I am not sure this fully qualifies as a conversion, but rather a technique that uses declarative. Read information into a data structure first, and then process it in the data structure instead of as it is being read in. This provides a kind of SeparationOfConcerns and can simplify error handling. The drawback is that it may require more machine resources.


I think the usual map/collect reduce/fold/inject and filter/select are examples of declarative approaches to explicit loop handling, are they ok here?

Where is any reduction in code occurring? I merely see alternate methods of writing the same code. With the qualification to avoid discussing the merit of the changes, I do not see the point of any of the changes proposed above. No less code is written and arugably more code may be needed to implement the suggested code segments.

It's basically useless when you have to type your data in, free-form, in a language like SQL. Remember that object.function(arg1, arg2, arg3) is itself data, something that's more obvious in the Lisp-syntaxed (function object arg1 arg2 arg3). There's no real difference between that and "INSERT INTO functions VALUES (function, object, arg1, arg2, arg3)".

The big difference, as I see it, is the possibility of structured data editors to manipulate that data. So instead of writing in textual code, you'd get a spreadsheet-like view that shows all fields in tabular format. And instead of delimiting fields with various punctuation marks, you can just tab between columns. SelfLanguage does something like this with objects, and I'd really love to see a MultiParadigm? programming language with a bunch of editors to edit different code structures. -- JonathanTang

What benefit would a spreadsheet-like view provide? -- EricHodges

Less typing, easier to see patterns. Switching between fields is just a tab, instead of the usual ( , , ); Can't get more minimalist than that. There's also the possibility of making some data implicit; for example, populating a hash table of objects in JavaLanguage usually requires:

  table.put(key1, val1);
  table.put(key2, val2);
  table.put(key3, val3);
  table.put(key4, val4);
The same table in spreadsheet form would have the symbols 'table' and 'put' be implicit, specified by the fact that you're editing this table. So you'd only have to type

  key1 val1
  key2 val2
  key3 val3
  key4 val4
And you can clearly see patterns in the code (data). If you've got repeating groups of arguments, they'll jump out at you, while they wouldn't necessarily do so in free-form text. It's easy for the important features of the code to get buried under boilerplate required by the language.

<This argument seems to have veered in yet a new direction. The statement above seems to be describing some sort of macro editor to create code rather than showing an alternative to the code itself.>

(You can get much the same effect by lining up columns in a text editor, but that's often hard to maintain unless you have tool support for it. And even then, it'll still usually be more typing, because you don't have the implicit/explicit option.) -- JonathanTang

Do you have a lot of source code that looks like that? Because of OnceAndOnlyOnce, I tend to put that sort of thing in a file or database and read it in a loop. My code has very little data embedded inside it. -- EH

That's exactly the point. It effectively is putting that sort of thing in a database - just not necessarily a BigIronRdbms?. The advantage is the tight integration with the host language. There's no way to store eg. LexicalClosures in an RDBMs, but they could easily be handled in an editor like this. And you wouldn't need to write the loop to read in the data - you would simply edit the data. -- JonathanTang

But would the values be inside or outside the source? Are you advocating a new editor or a new language? -- EH

In my Xbase days, it was usually easy to have both ControlTables and text editors open at the same time and switch focus between them. Another alternative is to program in a spreadsheet or spreadsheet-like utility and let text code be text code and tables be tables. There is a breif example of this at the bottom of TableOrientedProgramming.

You didn't answer my questions. It's common to have code editors, file editors and database management tools open at the same time. What are you advocating? -- EH

<I am a little confused. How does putting the values in a database table reduce any code? Do I not still have to perform the table.put() operations in order to do something with the data?>

Looping through a result set takes less code that 500 put statements. -- EH

<Weren't those 500 put statements required to get the data into the database? There is a difference between creating a data structure and copying it. Adding a copy operation does not reduce the code; it may time shift the execution of the code, but it does not eliminate it.>

Are you arguing that I should have 500 put statements in my code because the time cost is the same as entering the data in a database? Time cost isn't the issue. Source code is not a good place for data for many other reasons. Anyway, looping reduces the number of lines of code. The data in the database doesn't contribute to the line count.

<How is the data getting into the database? Wasn't a SQL script of 500 Insert statements written?>

Not in my experience. The data would have been entered through a spreadsheet, a db management tool, a TableBrowser, a CrudScreen, a text file, etc. Why write a SQL script to insert 500 rows??

<The assertion at the top was that a reduction of code occurred, other issues are not under discussion. Persistance of data is not the issue, population of data and the lines of code to support that population is the issue. Data population code must be written, the time must be scheduled, and people to write the code must be identified. True, there may be other reasons for using a database for persistent storage, but reducing lines of code is not one of them.>

Data population code? I've never heard of it. SQL insert statements seem like a lousy way to load a database. I either enter it by hand or load it from a file.

Again, this topic was not meant to be the place to discuss the merits of declarative-tilted programming.

I don't understand why anything on this page is considered declarative. -- EH

In data-centric declarative, you generally separate filling up a data structure and doing processing on the data structure. Another way of saying something similar is that repeating patterns are moved to a data structure of some kind.

In all of the procedural and object oriented programming I've done, I generally separate filling up a data structure and doing processong on the data structure. That isn't declarative programming by any definition I've ever seen. -- EH

How would you approach ChartingExample?

With a failing unit test. -- EH

Clarification desired.

I'd approach the ChartingExample by writing a failing unit test, as I do any project. I don't understand what that has to do with the topic at hand or my previous statement. -- EH

Something tells me we are in for a long terminology battle.

Not if you can show how separating data from code indicates DeclarativeProgramming, or conversely, how embedding data in code indicates ImperativeProgramming. -- EH

We wrote an interpreter in C++. The programs were stored in a folder with a bunch of flat files, one per class. You still need some behavioral code to "play" or run an operation, even though the operational data was stored in a data structure. We could convert our data structures stored in flat files to C++ global variables (perhaps not with today's compilers), and convert everything to C++. We had several operations: create (show), hide, arithmetic, send, receive, lookup (predicates), procedure (composite), move cursor, search ,reset, justify, trim, truncate, copy, ack, extend. The question is, what is the minimal number of operators one needs to implement a language? What cannot be made declarative? --AnonymousDonor

I never claimed that everything could be made 100% declarative. But a large portion of an application can often be converted to declarative, if one wishes to go that route. -t


See Also: ViewingAlgorithmsAsCollectionProcessing


EditText of this page (last edited November 23, 2014) or FindPage with title or text search