mobl: Een DSL voor mobiele applicatieontwikkeling

517 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
517
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

mobl: Een DSL voor mobiele applicatieontwikkeling

  1. 1. Zef Hemel, Eelco Visser
  2. 2. 230,000/day
  3. 3. 200,000/day
  4. 4. application development
  5. 5. Objective-C
  6. 6. Objective-C Java
  7. 7. Objective-C Java J2ME/C++
  8. 8. Objective-C Java J2ME/C++ HTML/Javascript
  9. 9. Objective-C Java J2ME/C++ HTML/Javascript Java
  10. 10. Objective-C Java J2ME/C++ HTML/Javascript Java .NET
  11. 11. AppStore
  12. 12. portability deployment
  13. 13. WWW
  14. 14. HTML
  15. 15. WebDatabases
  16. 16. WebDatabases Location information (GPS)
  17. 17. WebDatabases Location information (GPS) Threading
  18. 18. WebDatabases Location information (GPS) Threading Canvas
  19. 19. WebDatabases Location information (GPS) Threading Canvas Multi-touch
  20. 20. WebDatabases Location information (GPS) Threading Canvas Multi-touch Offline support
  21. 21. WebDatabases Location information (GPS) Threading Canvas Multi-touch Offline support Full-screen support
  22. 22. mobile web apps
  23. 23. HTML CSS Javascript SQL cache manifests
  24. 24. HTML CSS Javascript SQL cache manifests
  25. 25. user interface abstraction
  26. 26. user interface abstraction
  27. 27. var results = tx.executeQuery("SELECT * FROM Task"); for(var i = 0; i < results.length; i++) { alert(results[i].name); } synchronous programming
  28. 28. render page query database and process results ... time
  29. 29. render page query database and process results ... time browser freeze
  30. 30. render page send query ... process query result ... time
  31. 31. tx.executeQuery("SELECT * FROM Task", function(results) { for(var i = 0; i < results.length; i++) { alert(results[i].name); } }); ... asynchronous programming
  32. 32. tx.executeQuery("SELECT * FROM Task", function(results) { alert("Hello, "); }); alert("world!");
  33. 33. tx.executeQuery("SELECT * FROM Task", function(results) { tx.executeQuery("INSERT ...", function() { alert("Selected, then inserted"); }); });
  34. 34. mix of loosely-coupled DSLs poor tool-support for mixed-language projects lack of abstraction in UI asynchronous programming
  35. 35. demo http://confplan.zef.me
  36. 36. task 1: user interface http://mobl-lang.org/get.html http://webdsl.org/zip/devnology/eclipselinux64.zip http://webdsl.org/zip/devnology/eclipselinux.zip http://webdsl.org/zip/devnology/eclipsemac64.zip http://webdsl.org/zip/devnology/eclipsewin.zip
  37. 37. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  38. 38. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  39. 39. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  40. 40. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  41. 41. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  42. 42. application tipcalculator import mobl::ui::generic screen root() { var amount = 10 var percentage = 10 header("Tip calculator") group { item { numField(amount, label="amount") } item { numField(percentage, label="percentage") } item { "$" label(amount * (1 + percentage/100)) } } }
  43. 43. task 2: scripting
  44. 44. application test import mobl::ui::generic function fac(n : Num) : Num { if(n == 1) { return 1; } else { return n * fac(n-1); } } screen promptNum(question : String) : Num { var answer = 0 header(question) { button("Done", onclick={ screen return answer; }) } group { item { numField(answer) } } } screen root() { header("Calculator") var n = 2 group { item { numField(n) } } button("*", onclick={ n = n * promptNum("Multiply with"); }) button("+", onclick={ n = n + promptNum("Add"); }) button("!", onclick={ n = fac(n); }) }
  45. 45. application test import mobl::ui::generic function fac(n : Num) : Num { if(n == 1) { return 1; } else { return n * fac(n-1); } } screen promptNum(question : String) : Num { var answer = 0 header(question) { button("Done", onclick={ screen return answer; }) } group { item { numField(answer) } } } screen root() { header("Calculator") var n = 2 group { item { numField(n) } } button("*", onclick={ n = n * promptNum("Multiply with"); }) button("+", onclick={ n = n + promptNum("Add"); }) button("!", onclick={ n = fac(n); }) }
  46. 46. application test import mobl::ui::generic function fac(n : Num) : Num { if(n == 1) { return 1; } else { return n * fac(n-1); } } screen promptNum(question : String) : Num { var answer = 0 header(question) { button("Done", onclick={ screen return answer; }) } group { item { numField(answer) } } } screen root() { header("Calculator") var n = 2 group { item { numField(n) } } button("*", onclick={ n = n * promptNum("Multiply with"); }) button("+", onclick={ n = n + promptNum("Add"); }) button("!", onclick={ n = fac(n); }) }
  47. 47. application todo import mobl::ui::generic function fac(n : Num) : Num { if(n == 1) { return 1; } else { return n * fac(n-1); } } screen promptNum(question : String) : Num { var answer = 0 header(question) { button("Done", onclick={ screen return answer; }) } group { item { numField(answer) } } } screen root() { header("Calculator") var n = 2 group { item { numField(n) } } button("*", onclick={ n = n * promptNum("Multiply with"); }) button("+", onclick={ n = n + promptNum("Add"); }) button("!", onclick={ n = fac(n); }) }
  48. 48. application test import mobl::ui::generic function fac(n : Num) : Num { if(n == 1) { return 1; } else { return n * fac(n-1); } } screen promptNum(question : String) : Num { var answer = 0 header(question) { button("Done", onclick={ screen return answer; }) } group { item { numField(answer) } } } screen root() { header("Calculator") var n = 2 group { item { numField(n) } } button("*", onclick={ n = n * promptNum("Multiply with"); }) button("+", onclick={ n = n + promptNum("Add"); }) button("!", onclick={ n = fac(n); }) }
  49. 49. var pos = getPosition(); alert("Your location is: " + pos);
  50. 50. var pos = getPosition(); alert("Your location is: " + pos); var pos; getPosition(function(result) { pos = result; alert("Your location is: " + pos); ... }); continuation-passing style transformation
  51. 51. task 3: data modeling and query
  52. 52. entity Task { name : String (searchable) done : Bool dateAdded : DateTime }
  53. 53. entity Task { name : String (searchable) done : Bool dateAdded : DateTime category : Category (inverse: tasks) tags : Collection<Tag> (inverse: tasks) } entity Category { name : String tasks : Collection<Task> (inverse: category) } entity Tag { name : String tasks : Collection<Task> (inverse: tags) }
  54. 54. screen root() { header("Tasks") { button("Add", onclick={ addTask(); }) } group { list(t in Task.all() order by dateAdded desc) { taskItem(t) } } button("Search", onclick={ search(); }) } screen search() { var phrase = "" header("Search") { backButton() } searchBox(phrase) group { list(t in Task.searchPrefix(phrase)) { taskItem(t) } } }
  55. 55. screen root() { header("Tasks") { button("Add", onclick={ addTask(); }) } group { list(t in Task.all() order by dateAdded desc) { taskItem(t) } } button("Search", onclick={ search(); }) } screen search() { var phrase = "" header("Search") { backButton() } searchBox(phrase) group { list(t in Task.searchPrefix(phrase)) { taskItem(t) } } }
  56. 56. control taskItem(t : Task) { item(onclick={ taskDetails(t); }) { checkBox(t.done) " " label(t.name) contextMenu { button("Remove", onclick={ remove(t); }) } } }
  57. 57. control taskItem(t : Task) { item(onclick={ taskDetails(t); }) { checkBox(t.done) " " label(t.name) contextMenu { button("Remove", onclick={ remove(t); }) } } }
  58. 58. Task.all()
  59. 59. Task.all() where done == false && ... order by dateAdded desc limit 10 offset 5
  60. 60. Task.all() where done == false && ... order by dateAdded desc limit 10 offset 5
  61. 61. task 4: higher-order controls and native interfaces
  62. 62. control taskItem(t : Task) { checkBox(t.done) " " label(t.name) contextMenu { button("Remove", onclick={ remove(t); }) } } control taskDetail(t : Task) { group { item { textField(t.name, placeholder="Task name") } item { checkBox(t.done, label="Done") } } } screen root() { header("Tasks") { button("Add", onclick={ addTask(); }) } masterDetail(Task.all() order by dateAdded desc, taskItem, taskDetail) button("Search", onclick={ search(); }) }
  63. 63. control taskItem(t : Task) { checkBox(t.done) " " label(t.name) contextMenu { button("Remove", onclick={ remove(t); }) } } control taskDetail(t : Task) { group { item { textField(t.name, placeholder="Task name") } item { checkBox(t.done, label="Done") } } } screen root() { header("Tasks") { button("Add", onclick={ addTask(); }) } masterDetail(Task.all() order by dateAdded desc, taskItem, taskDetail) button("Search", onclick={ search(); }) }
  64. 64. control masterDetail(items : Collection<Dynamic>, masterItem : Control1<Dynamic>, detail : Control1<Dynamic>) { group { list(it in items) { item(onclick={ detailScreen(it, detail); }) { masterItem(it) } } } } screen detailScreen(it : Dynamic, detail : Control1<Dynamic>) { header("Detail") { backButton("Back", onclick={ screen return; }) } detail(it) }
  65. 65. external type LocalStorage { static sync function getItem(key : String) : Dynamic static sync function setItem(key : String, val : Object) : void static sync function removeItem(key : String) : void static sync function clear() : void } <javascript> firstapp.LocalStorage = window.localStorage; </javascript>
  66. 66. what else is there?
  67. 67. service DataProvider { resource getNearbyConferences(lat : Num, long : Num) : [JSON] { uri = "/nearbyConferences" } resource fetchProgram(conferenceId : String) : [JSON] { uri = "/conferenceProgram" } } web services
  68. 68. service DataProvider { resource getNearbyConferences(lat : Num, long : Num) : [JSON] { uri = "/nearbyConferences" } resource fetchProgram(conferenceId : String) : [JSON] { uri = "/conferenceProgram" } } function loadLocalConferences() { var position = getPosition(); var nearbyConferencesJson = DataProvider.getNearbyConferences(position.latitude, position.longitude); foreach(jsonObj in nearbyConferencesJson) { Conference.fromSelectJson(jsonObj); } } web services
  69. 69. location & maps
  70. 70. mobl::ui::ios mobl::ui::jq
  71. 71. mobl::ui::ios mobl::ui::jq mobl::ui
  72. 72. application confplan offline true title "ConfPlan"
  73. 73. future
  74. 74. adaptive user interfaces database sync more high-level controls web/native hybrid (PhoneGap)
  75. 75. http://mobl-lang.org http://twitter.com/zef http://twitter.com/mobllang http://zef.me

×