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": '' * Attribute-based (data-structures) * Logical (such as Prolog) 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 City''''''Name = "Not Found" SEEK(Cities, City''''''Abbrev) IF FOUND() City''''''Name = Cities.City''''''Name 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. (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. LexicalClosure''''''s 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 ControlTable''''''s 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'' ''Looping through a result set takes less code that 500 put statements. -- EH'' ''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.'' ''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??'' ''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