and so this talk is better scy builds with a M build tool um I've been an open source developer since 2012 many libraries in Scala apart from the open source Scala work I've also done a lot of work at companies like Dropbox and data brakes largely focus on on the developer tools and uh testing infrastructure so things like your Cloud Dev environments your cicd systems your test Frameworks integration testing systems and so on um I'm the author of the book handson scal programming so if any of you need a book to learn Scala or need a book to recommend to someone else to learn Scala Hands-On Scala programming is a great way to get started um and this talk about better Scala builds with a mill build tool has three sections first we'll talk a bit about what is mill then we'll talk about why you may be interested in this new Mill build tool then lastly we'll go into some details about how Mill works and from there you can learn about what really makes this build tool tick internally uh so first what is Mill so Mill is an open source jvm build tool it's actually not that new a project it started in late 2017 uh originally targeting Scala but more recently has grown support for Java support for cotlin it's current in the process of getting support for Python and JavaScript and other platforms Android it mostly does the same thing as s spt Maven and gradal but aims to be better easier easier to extend easier to use the performance is pretty good it's 4 to 10x faster than Maven 2 to 4X faster than Gradle for equivalent Builds on our benchmarks and it's used by quite a lot of scalar projects not the older ones that are still on SVT but lot of the newer projects that you probably have come to rely on so if you use SBT you probably you're using corsier the depy resolver many of you are probably using Scala CLI uh one not less uh I guess famous part of the Scala ecosystem is the Scala Hardware design area so chisel spinal HDL all are using the mill build tool these days and of course all of my libraries and ecosystem amonite where it fast pass these have all been using Mill for five seven years now I haven't touched SBT for literally more half a decade and it works great so Mill is pretty well battle tested in the in community and in the wild if you want to learn more there's documentation at Mill build.org um I won't go into all the details in this talk there's a lot more stuff there how to get started how to use it and so on so uh first let's do a small demo so over here I have a terminal um over here I have my small hello world M applic mil build for small hello wild application so this is a build. mail file this equivalent to a build SBT build. Gradle build. basil and so on M build files are written in Scala um and you can see there's a package statement there's Imports you have a object F extend scalar module so fza module we declare some configuration like scalar version is 23 14 IB depths is scalar tags and Main ARs and we have a test Suite which has is nested within food so it's food. test and it has it own dependencies and its own test framework configured so from here I can do Mill food. compile uh I can do food. test you can see I run the small test suet internally if I go and break the test Suite you can see the food. test fails um I can do food. run it ask me for an argument let's say d d text hello and see if say it outputs a hello there um I can do M food. assembly uh or M show food. assembly to show me the generated file and this is already a self executing assembly you can run it outside of the mill build tool so this is kind of just a hello world of what Mill is like this is a small like demo application just parel some command line arguments and renders a bit of HTML using Scala tags but it's just meant to show you how you can Define your Mill build using normal Scala objects normal scalar traits normal scalar definitions Imports and so on and that's enough for you to build your program so back to slides so far nothing we've looked at here is that surprising right you can compile test run package assemblies and run them up later but the question is like why Mill so you can already do all this using SBT using Gradle using Maven basil pants whatever you name it um so let's look at why you may want to use Mill rather than than the Alternatives um so there are three main reasons for this one is that Mill is in many ways more much more foolproof than many of the alternative build tools out there two is that Mill has a lot of support to help you with understandability of the build and understandability of the project structure and lastly Mill is much more easily extensible so you can just write code to extend your bill you're all Scala developers you know how to write scalar code and you can M you write scalar code to make your build do things rather than trying to configure some plugin that some guy wrote 5 years ago and abandoned on GitHub let's go through one by one so first the fool proofness one aspect of Mill that's interesting is the fact that the performance is generally pretty good and what's more interesting is you don't need to work for it the same way to work for the good performance in s spt or many other build tools for example M we do benchmarks across other build tools so we have benchmarks against Maven against Gradle against SBT the SBT comparison is using the Gatling code base where Gatling is a famous like open source Scala load testing framework so Gatling has existing build which is an SBT and we ported it manually to a mill build took about an afternoon and the mill build is not 100% complete but it's complete enough that all of the Gatling code compiles all the Gatling test pass and it's enough for you to actually do real work with the Gatling code base using our new Mill bill that took like 4 hours to write so gatherling is not a small project we are looking at 80k lines of Scala code 800 files over 20 sub projects so it's quite a meaty project like most of the the uh projects we use for our benchmarks in comparison so what's interesting about these benchmarks is when you start benchmarking SBT you realize SBT is two different performance like um characteristics one is it's cold performance where run SBT compile SBT run SBT test from the command line and every time you run it it spins up a new SBT server and runs everything from scratch and this works okay takes but takes several seconds to get anything done the second set of benchmarks is the hot spt numbers where if you open up spt console you run things in spt console then you get much better performance like for example parallel clean compile of the whole Gatling codebase is twice as fast in a hot spt console and clean compile of a single module is 10 times as fast in the scpd console as is running spt from the command line but you pay a price for this speed in convenience so you need to open your SVD console can run things if you change a build config you need to remember to run reload if you don't do that your you'll be running stale config and your Bild will probably screw up if you run something it taking too long you run control C to interrupt it you need to remember to go back into SBT console before you do things again and so there's a bit of a dance here you have to Ed to manage SBT console in order to get good performance and on the other side the obvious naive way of using SBT you get poor performance so Mill isn't that much faster than SBT in if used ideally so you look at the numbers here Mills incremental compiles noop compiles clean compile of single module even the parallel clean compile is off by just a few seconds it's not like that much faster but thing about Mill is that Mill basically automates all this SBT Long Live Process Management dance for you and it's all built in so you just run mil from the command line and mil will spin up a long lift server for you keep it warm it will it will reload the config automatically when the config changes if you kill the server for some reason like control c will reload the server and this all happens in the background you don't need to install a separate build server or do anything to make it work or turn on the config this is the default behavior and it works very well so that's kind of the point of what I mean by foolproof in that with Mill you don't need to worry about configuring a build tool or using a build tool correctly to get good performance like it's not fast in SBT but it's just easier to get the good performance out of it than is using a traditional SBT build system another aspect of uh Mill which is easier to use and more foolproof is the plug-in ecosystem so SBT has a very big plugin ecosystem and that is both a blessing and a curse it's a blessing because anything you want to do with SBT someone's probably written a plug-in for it and it probably does more or less what you want the curse is that in order to to do anything with SBT you need to go and hunt down a whole zoo of plugins and find all the right versions find all the right documentation for right versions and wi them up in your code base or your build system in order to use them to work on your code so going back to the Gatling code base which is what we use for comparison Gatling requires six plugins to do assemblies gmh benchmarking J Jupiter junit 5 testing Scala fix Scotland spotless Auto formatting and mil also has plugins but in this case Mill requires external plugin from for for Scala fix assemblies are built in we saw earlier JM junit 5 uh cotlin Auto formatting in all the different jvm languages is all just built into Mill and it's not terribly complicated it's not like these the functionality built into Mill is superior to the functionality in open source spt plugins but it's just easier to get started where if you want to get started with the mill project you can just use Mill and you get 95 99% of what you need built in without having to go on The Grand Tour of the Scala open source ecosystem and assemble a Avengers team of all the different open source contributors and the plugins that they wrote so that's about being foolproof next let's look about what being understandable um so there two aspects I look into one is ID support so I'm going to go back to code and here we have the gatherling build for uh in Mill and inbt let me pull this up correctly so here's Gatling build. Mill file this is one we wrote for the comparison here's gatling's original build spbt file and if you look at these two files they're not actually that different so for example let's look at Gatling Gatling core and let's jump to that Gatling core here so over here we have Gatling cores config for both Mill and SBT uh if you can't read this just let me know in the Discord or chat I'll make it bigger um and what's interesting to First note is that these two Snippets of code don't actually look that different like sure they have slightly different spelling uh SBT says lazy Val core equals Gatling module uh Mill says object Gatling core equals extends Gatling module the spelling is different but in generally it means the same thing so you know they both are in a Gatling Das core uh subfolder they both have dependencies on net util on uh quick lens they both have dependencies on Commons and Json path and they both have know test dependencies on the last two they both have settings on core Java dependencies which it's basically the same list in both let me pull this up bigger so I C dependes the same list in both so given that it's so similar like what's the difference here you see intell is a port for both SBT and Mill they're both Scala files and you can kind of navigate around them I I showed you how to jump to C dependencies and it works so why do I say Mill is better um the answer is what happens when you go slightly deeper than just poking around your superficial code base for example let's say you are a new developer you don't know what library dependencies is or alternatively you're an existing developer and you have to find how Library dependencies really is used within your spt build like sure you've cargo cultered some stuff of stack Overflow you read the docs you're not clear you need and you want to debug something and you want to see okay I'm setting these Library dependencies where is this data actually going who's using the stuff I'm setting like these are obvious questions that people ask all the time in their normal application code and they ask the same questions in their bill code so you may want to put up a documentation you'll find that spt and inj gives you nothing that's the first kind of red flag next you try and jump to definition for Library dependencies which does work except it brings you to like a face full of decompiled bite code okay so this is again not great like if you know what library dependencies already does if you already know what library 10 penes does you're fine but if you don't know you're kind of hitting a wall here there's no way for you to find out in your IDE what this uh what this key or this task or this uh workflow is doing so what do you do next like who knows so what you typically do next if you want to do it kind statically is you go to this magic file keys. Scala in SBT repository and grab for Library dependencies so if you know to search for keyot Scala and you know that to to to grab it you'll find that it has one line of documentation declaring manage dependencies so this is better than nothing at least I know I I know what someone said about this even though it's a bit short but what about what's next right like who's using Library dependencies just now you saw it was someone was using Plus+ equals what's the value before the Plus+ equals and if you grab for it within this file you can't really find anything and the next thing you you do is You' go to the SBT project search bar search for library dependencies and somewhere in these 200 source files you'll find where it's being set to and that's really often how people figure out how they use how to use SVT and if you can't figuring out maybe you're not smart enough or not experienced enough with SVT to do this then you're in trouble right you're kind of stuck you're hitting a wall where sure you can cargo cut what it means you cargo cut what some guys on stack Overflow or what was written in the Docks but there's no way to investigate what library dependencies does using an IDE so let's see how Mill is different so Mill is called IV depths instead of library dependencies but it means the same thing it's a list of dependencies depends on um first if you ask for a do mentation you get documentation so any IV dependencies you want to add to this module in the format uh or double colon Name colon version for scal dependencies or or single colon name col version for Java dependencies so okay we off the Good Start you have documentation next you'll see that intellig has this thing in the in the um gut which says is intell knows that this is an override and it knows who I'm overriding and it knows where those overrides are defined so we can go to for example the Java module definition which is overden and see before I overload IV deps it has a it is a task with a empty Aggregate and aggregate m is like a sequence of dependencies of depths okay so already useful like now I'm better than SVT that just in my editor I'm able to find documentation I'm also able to find the default value of this task what's next I can go to IV deps I can search for it I can start finding where it's being used and Trace its usage throughout the the mill build graph IV depths here is used here in all IV deps all IV depths is used in transitive IV depths transitive IV depths is used in resolved IV depths resolved IV IV deps is used in compile class path and comp compile class path ends up being used in uh the comp the compile task so just like that poking around my IDE I'm able to navigate from my build to the setting that I'm setting within my build to how it's being used within the Upstream Mill like build pipelines that come bundled you know the compile Scala and you can go arbitrarily far right so here I'm looking at this compile task up in my Upstream uh Mill kind of Library code that my editor is showing me if let's say I look at all source files what's this ask for documentation I can jump to it you see all source files fed to Java compiler it's you can see the implementation right in front of you it calls a light lib find source files and all sources what's all sources I can jump to that all sources is sources plus generated sources what sources I can jump to that sources is the Source path of the module which is kind like the base folder of the module and the SRC folder within it so this is what I mean when I say Mill has better um ID support than SBT and most other build tools all build tools have some kind of ID support where you can jump to things but often the things you jump to is not very useful here I show you SBT but if you try and jump around the Gradle code base using intellig whether Gradle groov or Gradle cotlin you'll end up hitting the same thing where hitting these decompiled Subs that don't really tell you anything in contrast jumping around the mill codebase using I intell you're literally navigating up and down the task graph you can really see how this these data how these Keys configuration and files are generating are flowing through your build code and ending up in the being used in the tasks that you need them in so this is again nothing that is special to Mill those of you using intell and your application code are doing this every day day in day out navigating around your play framework website navigating on http4s web server using these kinds of jump jump to definition and find usages and what Mill does is it brings the same experience to your build code to allow it to be totally kind of transparent rather than being an opaque black box so um that is back to slides that's ID support demo the next demo I'm going to show you is the Chrome profile so when you when you run something using Mill it can take some time like any other build tool so here's my Gatling code base in my terminal let me pull this up nicely uh on the left you see the Gatling build file on the right see a terminal with G Ling loaded I can do mil clean and n and milore compile so you can see M like SBT has a multi-line um prompt that tells you what is running um the first time you run it like compiling any SBT build file scal build file takes a moment then after while it warms up so you can see in the bottom of this prompt terminal what what is doing at any point in time it's compiling gatherling Commons core compile may take a few seconds uh you can after Gatling call call compile finishes it kicks off a bunch of Downstream tasks among them Gatling call test once Gatling call test finishes you see even more task kickoff after call test finishes so just looking and eyeballing this promp can get some intuition of what's taking up your time but it's often not enough right you you really need something more in order to make some actionable outcomes to improve your build experience so what mil provides in every single command is this Chrome profile so this is a Json file that tells you exactly which task started when on what thread and alone is not very useful where it becomes useful is when you load it into this chrome colon tracing UI that's built into every Chrome browser you all have on all the computers I bet you all didn't know this exists cuz most people don't know this exists but it's very handy if anyone needs a ad hoc profile that you can speed in some Json to Chrome comes built in so I just drag my Chrome profile into Chrome and voila you see I have a interactive visualization of where my time in my Mill build command went you so I ran double uncore compile earlier well here you have Gatling compile taking up time Gatling call test taking up time uh Gatling comments taking up time and so on and what's interesting here right even if you don't know anything about Mill even if you don't know anything about Gatling codebase you can already probably start having some ideas of what can be improved Gatling C seems like a bottleneck maybe we can break it up into sub module smaller sub modules that can compile in parallel Gatling core test compile also seems like a bottleneck and Gatling core test it seems to be required before Gatling HTTP test compile starts do we really need to compile the entire core test Suite before starting the HTP test Suite or does http test really just need a few core like test helpers that can be broken up in some gatherling test details library that compiles faster and will allow all this stuff on the right to move further to the left so this is the kind of thing that Mill gives you by default and although other build Tools in theory could give it to you in practice it's difficult to set up and you probably won't do it on a dayto day basis like for SBT you can probably find a plugin to do it for Gradle you might going need to go pay for gradal Enterprise Bild scans and go hook up to the Gradle Enterprise backend web services in Mill it just gives you a Json file that can load into any Chrome browser that you all already have and immediately start getting actionable insights about the runtime characteristics of your build and what's taking up time and what you can do about it so back to the slides um that's the understandability angle the ID support introspection tools lastly let's look at extensibility so most build tools require extensions be publish as plugins you want to do F you need the F plugin want to do bar you need bar plugin so on so forth you don't have a full plugin you need go right one you go learn some plugin API plug-in framework the bar plugins abandoned because some guy wrote it 5 years ago and has an updated today you need go bring up the bar plugin up to date Mill does have plugins and I showed ear for example Scala fix is a third party plugin but you don't need them as often because M lets you write code and import any Maven Central Library to use in your build scripts and let me show you an example right so over here I have um let me bring this up over here I have like the minimal Mill build file for Scala so this is um this is object F extend scal module with the scal version and nothing else right I can compile it f. compile and it works but let's say I want to do something custom let's say I want to include the line number the line count of my module in as a resource for the file for the application use at runtime so this is a bit of a synthetic example but kind represent devolve all the weird things that people need to do in their builds in realistic applications maybe you need a bill of materials to publish for security purposes maybe you need some custom build metadata to publish with your production Docker container for debugging in production maybe you have some special IDL that your company users maybe you need a protuff compiler or Thrift compiler to generate code there's all sorts of requirements that people end up needing in real builds and while you can sometimes find plugins for them often these are very bespoke and very unique to each individual business so back to our line count our functionality right let's say I want the line count as a resource file to use at runtime in Mill adding a new task is just using a def let's say line count equals task I can add documentation like say count the lines of code in this module and I can start using the other tasks in this uh module to compute this line count for example if I want to count the source files s Source lines I need to go for all the source tasks I can use intell to pull up the documentation it looks like I want all source files which is all individual source files fed into zinc compiler but I can see documentation for all the others if you're curious what they do call it because it's a function I can map to get the references path references I can read their lines uh I can get the size of the nut lines and I can sum them up so this is all you need to do to write the mill custom task now that I have this I can do Mill show uh food. line count see line count is 17 which is correct if you look at this it says uh this is 17 lines of code excluding the trailing uh new line um I can inspect food. line count you can see that yes it's called food. line count it is in build. Mill line 8 that's what you expect you can see that it has my Scala doc including the typo the L lint of code in this module the dependency on food all source files is captured you can expect from the command line and this this is everything you do get in SBT build as well but with Mill it's just so easy to write any normal method and turn it into a task just wrap it in TK and Cly Braes so now I have my line count task but how do I wire it into resources so M resources are done handled using this resources task and you can search for it you can pull up the documentation it says the folders where the resource files of this module live if you so I can override it say override def resources I get auto complete even I override as a task and I say os. write to task destination folder um line count.txt um let's say line count. twring format this nicely and I'm going to say super. resources Plus+ a path ref to my task. destination folder so every task in Mill gets a destination folder by default that helps us keep things from having side effects that collide with other tasks we call it task. desk desk and now I've overridden my resource folder I can show my food. resources it has both custom Scala SL food resources is original super resources that comes built in but also has this out F resources. Des folder and this is a custom task desk folder that I'm appending to my resource path if I look inside this resource address folder you'll see is line count.txt I can look at lineon txt C it you see has a number 17 and now when I mail uh f. run you can see it's able to load the line count from line count txt at runtime using this Java class loader get results at stream apis and printed out at runtime so line counts a bit boring let's do something more exciting let's say I want it as not the text file with the number but as a HTML file so Mill doesn't come built in with any HTML templating Library you can see this doesn't work you can run it in the terminal intell item both give tell me scal tags doesn't exist here but Mill allows you to import things very easily so you can just say import dollar IV which pulls things from Haven Central and just say com. leh Scala tags 0.3.1 now if I reload my project give it 5 Seconds you'll see it now intellig is able to recognize Scala tags. text you see that my terminal is able to run it and compile scal tags. text and now I can Define my new task line count HTML equals task F uh let's say it's a div with H1 line count and p uh of the line count value and I render it as a string and bottom instead of using line count I use LINE count HTML and now when I run f. run you see that my application code now get HTML template to as a resource that can print out and otherwise manipulate at runtime so again like rendering a HTML file with a line count is kind of a silly example but it's kind of Representative of all the weird things that real world builds and real world projects end up needing to do and you end up not just need to write code you need to use libraries libraries from Maven Central because that's the libraries you're using an application code that you want to use in your mil in your build code and with Mill not just writing code with like using like reading files and from dis and Counting the lines is easy but even pulling libraries like Scala tags from even Central and using those your in your build is really easy too and there's no Mill line count Plugin or Mill Scala tags plugin here you just import the libraries and use them just that you within any Scala code base so that's this plugin free plug-in free accessibility that M provides you can directly write code or WR use any libraries both of which you already know how to do because you're Scala jvm developers so that's a quick tour of why Mill like cuz it's foolproof cuz it's uh understandable cuz it's easily extensible for last few minutes let's talk a bit about how Mill works there are three sections here that I'll go through in turn first the idea that in Mill modules are just objects and tasks are just methods so when on the left you see this a minimal food Java module unlike a scal module you don't even need specify a scalar version for Java modules and it is object f is literally a Scala object and Java module is literally a Scala trait and like any object inheriting from a trait you inherit all the methods like in this case a simplified version is sources compile class path resources in assembly and you know they call each other the data flow flows through like the sources get pass a compile get p a class path get P assembly and so on you already know how method calls work and call graphs work and you know how inheritance works so this should not be surprising when you start doing custom stuff in your Mill build for example defining your line count depending on all source files and defining resources overriding the previous resources calling your line count but also calling super resources this adds methods to your object just like any other method definitions with overrides and Superstars like you already know how override and super works so this behaves exactly like that and it results in the build graph looking like this where I have food sources being used in L count in food resources which still uses a super resources and both resources and class Parts still being used in assembly so once we have this graph that Mill captures Mill is able to automatically make decisions around paralyzation for example it knows that the blue tasks can run in par with the red tasks because they don't depend on each other but assembly and green needs to wait for both blue and red to finish because it does depend on both um Mill allows you to automatically C Mill helps automatically cach all your task outputs to dis so Mill for example knows food. line count has a name food. line count so you can say I'm going to cash it in outline count. Json as using you using the up Pickle Library similarly F.C compile get cash out file. Json with files being put in out// compile Des similar for assembly where the metadata goes to a Json file and and the files go to a desk folder this is a task. des folder we saw earlier when you make changes to inputs for example you change the resources folder that is now called super. resources Mill is able to just do a simple breath first search in this graph and say that hey resources is Downstream of food super resources so this needs to reevaluate assembly is Downstream of that so that also needs to reevaluate on the other hand line count compiles class path none of these are Downstream of the ch inputs so we can just reuse the cast Json which was generated automatically so what's most interesting about this whole setup is that you look at the code on the left there's nothing here related to parallelization caching introspection invalidation and so on you don't see anyone Computing cach Keys you don't see anyone writing things a dis and deleting them on dis you don't see anyone taking locks or having semaphor or spawning threads or Futures to paralyze things or actors none of of that occurs here like the code on the left is literally pure business logic I'm taking the line count is all source files reading the lines summing them up resources I'm overwriting I'm writing out the text file as a resource and I'm returning it as part of the resource path so Mill does all the other things for you and this has two advantages right so one is it's much easier to write the code like you can do the even a new grad who doesn't know anything about Scala can probably fumble through the stuff on the left and more or less get it working which cannot be said for equivalent SBT your Gradle build the other thing is that because all that stuff is automatic it happens much more aggressively than it does in SBT grad or other build tools or May for example line count here is cashed in this case of line count it's kind of trivial right runs very quickly but I'm sure many of you have SBT builds where your code generator runs every single time you run a command because you didn't bother to put in the effort to cash it because it's not automatic or maybe your resource generators always hashing and always reprocessing your resources because you forgot to cash it in Mill that never happens because everything is cached automatically and therefore in any large Mill build it typically ends up being a lot faster than your SVT or Maven builds just because all the miscellaneous utility tasks you end up having are cash and paralyzed without having you do anything so that's this modules objects task and methods idea the next uh bullet point is how this actually is implemented under the hood so if you look at this def IV depths here on the left you'll see that okay I dep IV depth is an aggregate which is I can see with some scalar dock there's a IV stre interpolator Scala organization colon Scala reflect colon scalar version so this is just pulling in the right scalar reflect artifact for whatever like scalar version you're using right and you can show it you can inspect it from the command line it prints out the name file line number all this stuff but we may Wonder like how do we get this information at runtime you don't normally get method names at run time you don't normally get the file file name line number at run time you certainly don't get a scalar at run time and me you have a method that calls other methods you can't just look at the inputs at run time so what's going on here so what's going on here is that when you write the code on the left it expands into this code on the right so and it does this through a whole range of different techniques so we have we have some build time code generation like Scala CLI or ammonite or the Scala repple does for the Scala doc we have a compiler plugin that grabs the scal dock puts it in a Java annotation which we then use Java Reflection to fish out that run time so you can print it out uh in order to get the inputs here so you can see what methods this IEX method calls we then have a macro implicit conversion that turns this direct style So-Cal direct style method call into a applicative functor zip map data structure so most of you are probably familiar with monads few of you probably use applicative functors on daily basis but they are like a less flexible version of monads allows you to therefore manipulate and analyze them more easily for example applic functors that you statically analyze their dependencies without having to evaluate them whereas monad you have to evaluate them first so for Mill I want to be able to look at what my build graph looks like before evaluating my build and so I use an applicative functor which then their operation is normally called zip map or app depending on what background you're coming from line number file name and and the name of the method itself all come from macro implicit parameters from the source code Library source code line file name and name and the Ser Json serialization comes from the uple library as a normal implicit type class so all this seems like a lot right but the thing is when you are writing mil code you write this and generally all the other stuff just stays out of your way 99% of the time 1% of the time you may need to worry about something to do with that but vast major majority of the time you just write your easy code you get the nice stuff on the bottom left all introspection parallelism caching and validation for you and only the mill maintainers need to deal with this mess of complicated techniques and implementation details so that's how it is implemented so last thing I'm going to touch on uh before we finish the talk is the use of the direct style DSL instead of a stage DSL so Mill has um yes are you talking are you just a five minute reminder I'm sorry okay yeah so if you look at the difference between the mill file on the left and the equivalent SB file on the right you see that Mill they're both Scala SBT is not more aose than Mill Mill is not more concise than SBT um but what's interesting thing is that the middle code on the left looks like the code you write on a day-to-day basis with objects extending traits with definition Scala doc Imports packages and so on the SBT code on the right is technically Scala but it doesn't look like any Scala code you've probably touched outside of SBT code base you have these lazy ve line count equal tasky things with this Pudo Scala do that's not really Scala do and you know line count is kind of a method definition but it's not really a method definition actually lazy Val but it's used like a method definition and type signature here looks different from a type signature here if you're using a colon if I put one and generally all this stuff on the right looks like Scala but actually isn't really Scala and that there in lies a problem with a lot of SBT tooling and SBT uh I guess intuitiveness and understandability so if you look at this from like a multi-stage program point of view SBT is really two programs one is the stage one program using Scala lazy Val Scala method calls scalar strings and other data structures that evaluates and for this first program intellig has no problem navigating around your deaths and valves and other helpers within your build file we saw that earlier in our gatherling example the problem is this first program is not enough to actually understand what your build is actually doing your first program all it does is construct the data structure that is interpreted later using the stuff in the top right and the stuff in the top right are things intell does not know about intell does not know about file function. cach to cach or uh task outputs inell J doesn't know that task overrides work differently from Scala method overrides or that settings lists work differently from uh scalar traits intell doesn't know about the details of how sub projects work and how they differ from normal objects in Scala so although SBT is not nominally written in Scala and it's using a Scala DSL um the Scala part of it is honestly the less interesting part of it and when you jump around it doesn't tell you anything at all and the more interesting part about it for example how the four-dimensional config scope hyper Matrix Works in SBT that stuff is totally outside of Scala and therefore totally outside of the expertise both of intell and vs code AS tools as well as any scolar developers that you may be employing in order to work with this Bild like your scolar developers know the stuff down here your scolar developers don't know the stuff up here so Mill does this differently Mill rather than having a two-stage program that you run some scalar during the program that then gets interpreted later using some more different techniques and uh Concepts M work very hard to just squeeze everything into the first stage and we saw that earlier right with the crazy code generation macro implicit conversion applicative functor transformation thing we saw with the compiler plugins grabbing the Scala doc to put it available at runtime so all that's honestly a bit crazy and it takes all that work to squeeze all those Concepts into stage one of your Scala program but the benefit now is that once it's all in stage one it's stuff that intellig vs code and your day-to-day Scout developers know about about your new grad who took Cera Scala knows how override Works your Java developer who Tri fresh out of school knows how super works it works same as in Java your methods are your task are just methods your call graph is your task graph your object suest modules you you all know how reuse VI trait work stackable traits uh abstract methods all that's exactly the same you're all already writing Scala doc hopefully so you don't need to learn this new doct string syntax and this is what really makes Mill so much more intuitive not just for human but also for tools in that it squeezes everything into the first stage of your scal program so M programs despite all the magic look like Scala and behave like Scala and this is something that SBT and other many other Frameworks get I think have problems with not just SBT but things like cats effect sometimes zo AA streams they all have this two-stage evaluation model where the first stage in Scala is great but someone needs to go teach intellig about the second stage otherwise you get no help at all and because intell only knows the stuff in the bottom right so that's how Mill works just to wrap up I think have one minute left we talked about what is Mill why use Mill and how does mill work um I won't repeat all this you can read it yourself there's more documentation online at Mill b.org if you want to get involved and I think hopefully you found this interesting and if you want to get involved we can all we can all work together and make make a better build system for the scholar Community going forward thank you Back To Top