Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Adventures in Immutability

This assignment studies how immutable data structures play out across Elm, Ruby, and Swift.

You will start with an Elm app, doing a modification exercise that will help you understand its structure.

You will then work with Ruby and Swift ports of the core logic from that app. Both use a mutable model, but are otherwise roughly identical to the Elm version. You will study what it takes to make the model immutable in both languages.

As always, start by forking and cloning this repository.

Part 0: Elm

Goal: Practice reading and working with Elm. Understand the structure of an Elm application.

Setup

Review The Elm Architecture. Make sure you have an understanding of Elm’s particular notion of immutable models, messages, and views.

One-time setup:

cd elm-todo
npm install

This will install elm-live. It serves up an elm app in your web browser, and reloads your changes as you make them.

To launch elm-live:

# Mac, Linux, Windows Powershell maybe?$(npm bin)/elm-live Todo.elm --output=elm.js --open
# This might work on Windows; please let me know:
.\node_modules\.bin\elm-live Todo.elm --output=elm.js --open

Now you can make changes in the code and watch the browser update. Yay!

Your task

This is a stripped-down version of the elm-todomvc demo project.

A programming saying I love:

Structure your code so it’s easy to delete.

The current version of the app lets you edit a todo item after it’s added by double-clicking on it. Remove that feature. After you are done, double-clicking a todo item will do nothing, and it will not be possible to edit an item after it’s added to the list.

This will require careful reading of the code. Make sure you understand where this feature lives in the code, and that you understand what you’re removing. Be careful not to leave any dead code that serves no purpose once the feature is gone.

Hints:

  • The changes you need to make are in Todo.elm. Everything else in that folder is just infrastructure.
  • First figure out which parts of the model and which messages relate to this feature. Remove them first.
  • Then use Elm’s type checking to see what parts of the update and view code depend on what you just remove. Reason carefully about what also needs to go.
  • Pay careful attention when removing view code! What pieces of the surrounding context need to stay? What pieces no longer serve a purpose? (Contact me if you need help understanding the HTML structure.)

Part 1: Ruby

Goal: Gain insight into how Ruby does and does not facilite immutable data structures. See the relationship between the common style of Elm vs Ruby code and the different features of those two languages.

Setup

cd ruby-todo
bundle # shortcut for `bundle install`

Now test:

bundle exec rake test

The tests should all run with one skip:

......S..
Finished in 0.002792s, 3223.4958 runs/s, 5014.3267 assertions/s.
9 runs, 14 assertions, 0 failures, 0 errors, 1 skips

Your task

This a Ruby port of the model, message, and update portions of the Elm app. It also includes a super-simple simulation of Elm’s internal engine, located in lib/engine.rb. This is a not a fully working app; there is no view code. It is just the guts of the todo app, plus some tests.

This code hews closely to the structure of the Elm version, with one big difference: the model is mutable.

Note the “supports time travel” test at the bottom of test/todo_test.rb. If you comment out the “skip” line and let the test run, it will fail. Why? Because the model is mutable, so you can’t keep snapshots of how it used to be along the way.

Your task: alter the code to use an immutable model so that the time travel test passes.

Hints:

  • You do not need to add or modify any tests.
  • It will be easiest if you leave the time travel test alone at first (still skipped), and get the other tests to pass with an immutable model.
  • Start by making the model itself immutable by replacing attr_accessor with attr_reader in lib/model.rb.
  • You’ll need to modify the Engine.run_with_history method to assume that apply_to returns a new model instead of changing it in place.
  • Now update lib/messages.rb to make all the tests pass again.
  • Once you have the existing non-skipped tests passing, the time travel test should pass too.

Part 2: Swift

Goal: Understand how Swift structs handle immutability. See the difference between their syntactic similarity to other OO languages like Ruby, and their semantic similarity to Elm.

Setup

On a Mac, make sure you have Xcode version 9.2 or greater.

On Linux, make sure you have Swift 4.0 or greater. This assignment theoretically works on Linux, although I have not been able to test that. Let me know how it goes!

Reminder: Swift does not work on Windows. The lab machines in 254 and 256 should have a working version of Swift installed.

cd swift-todo
swift test

You should see 8 tests passing:

Test Suite 'All tests' passed at 2018-04-06 17:23:31.887.
Executed 8 tests, with 0 failures (0 unexpected) in 0.093 (0.093) seconds

If you are on a Mac and you want to use Xcode for editing Swift so you get nice things like autocompletion, run:

swift package generate-xcodeproj
open Todo.xcodeproj

You can run the tests in Xcode with cmd-U.

Your task

This is a Swift port of exactly the same things as the Ruby project above, and your task is the same: alter the code to use an immutable model so that the time travel test passes.

(You will see the time travel test commented out in Tests/TodoTests/TodoTests.swift.)

The first step is a little different from Ruby: in Sources/Todo/Model.swift, change each class to a struct.

From there, the process is the same:

  • Modify runWithHistory to assume that apply(to:) returns a new model instead of changing it in place.
  • Update the model and message code so the tests pass again.
  • Once you have the existing tests passing, uncomment the time travel test. It should pass too.

You will find that most of the above requires very few code changes. You will, however, run into some vexing problems in Message.swift. Contact me for hints!

Things to Think About

These aren’t to write up, just for you to reflect on:

  • Beyond the obvious (static type annotations), are there deep structural differences between the original mutable model code in Ruby and Swift?
  • Why was the problem of changing to an immutable model so different in Swift than it was in Ruby?
  • What language-level support could Ruby give to be more similar to Swift? Would it be a good idea? What parts of the underlying language model would make that easy or hard? Sensible or not?
  • What language-level gymnastics does Swift have to do to make structs be truly value-typed? Where does it depart from familiar OO languages because of this?
  • Why didn’t I give you a fully working Ruby web app and Swift web app to correspond to the original one in Elm?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages