Devreal

Scala War Stories

Event: Silicon Valley Scala Symposium

funconf 2013, Paul Phillips: Scala War Stories

Recording: funconf 2013, Paul Phillips: Scala War Stories

all right here we go there will be slides like this one with people's faces and quotes please just shout out if you know who they are this one is Donald Rumsfeld this is the slide that says Who I am for the very first time I'm still Paul Phillips still working on Scala see for the last 5 years still not speaking for a type safe but still employed type safe for the time being and yeah and I worked very hard on these slides and most of that work is invisible so this is not the product of like lots of hard work it's what's it's the residue of the product and lots of hard work it's very much not the same thing and the reason it worked out like that is that I kept getting like trying to chase down a terribly difficult problem that had plagued us for years so of course that's not exactly the quickest process and I'd get to the point where the war story would be and determined that it was our self-inflicted you know shooting our own feet that's not a good war story to me like there should be something legitimate you were up against right I mean some external factor that you had to work around somebody else made this happen not like I did it to myself so because I had to cut all those there wasn't as much left as I would have liked it says that if you find your time has been spent I owe you dinner nobody collected on that at JVM Lang it may be because I was impossible to find but that that's genuine offer if you can find me tonight in case you've never heard of Scala and are here for some reason maybe beyond just pure hype that is a little chart of languages and to look at that this is like everybody else right because that's like a whole little cool kid group and then there's a good sized gap and then there's us right out in front you can't even see closure here which I cut right there so the closure would just miss Oh what differs is its upward moving chart what access stop with your focus on extraneous details look at that line I honestly this is something weird like number of things on github and number of things on Stack Overflow I don't know it made no sense to me doesn't matter the important thing was that they clustered the way that I wanted for this slide the the source material is red Munk there from like last month so you know you can just decide how legitimate that is I don't know and then that's my personal credentials that's the bonfire into which I have burned off the last five years of my life yeah that's that's it that's all that's my resume like if I was sending out resumes that's what I would put say either hire me on this or no cuz I got nothing else we are our time is in large part and well in large part there haven't been that big and us but even now when there is a bit of in us our time is completely swallowed by the rest of the compiler we never get a lot of time to really think about bytecode maybe until recently so there are issues that we have that again like the aforementioned foot shooting business that you know that people with greater sophistication might say like what do you do it that way for that was not wise and they would probably be right so this is all just kind of disclaimer to that end that like we under you know I understand anyway and acknowledge the that in expertise is the source of a lot of our difficulties but even so they remain difficulties so there we are yeah but it's hard to it's really hard to communicate like to what extent the implementation has determined how things have worked out for the last five years because the difference between a language implementation where you can say well I wonder how things would work out if we did things slightly differently and just try it and the kinds where you have that same thought but then a week later you haven't been able to make it do it slightly differently without exploding all over the place very large because your opportunity to actually investigate and explorers very low you're just thrilled to get anything working and then you're tempted to run with that so war stories could possibly include friendly fire you know generals like you know paths of glory ordering you to you know do the unwinnable charge third parties pitting armies against one another that's that translates to like companies wanting you know stuff in the language that's very much to their interest but maybe not in the general interest and you know we have a lot of charging machine-gun nests on horseback the long and the short of it is though I'd like these are attempting to get to the ones that are not all those things and are more like legitimate there's a thing you know there's a some kind of fortress and we need to get over the fortress so that we can have working equality or whatever alright it's your first opportunity who's that no googling yes that's right the fog of war so applicable for us what's it could the Carl von Clausewitz so we have a number of constraints that complicate everything in the stories to come here the biggest one and the fuss is most pleasantly defined as Java Interop but closely competing for the biggest problem is separate compilation so by this mean we mean we can't choose an encoding for things when we're trying to take elements of the Scala language and make them work at the bytecode level where we don't have the luxury of choosing an encoding that would require scene to source files at once you got to be able to compile this one and then compile this one and have it work this inflicts a great deal of pain furthermore you know to have to interoperate with Java when Java expects bytecode they very much model sort of the Java lang which that's a luxury they have in Java is that bytecode is sort of a translation of the Java language when you write protected in Java source you get protected in the bytecode so not only is like basically the whole world is out there kind of expecting things to go that way we can't do things that way at all and then you know the last sort of the catch-all saving your life if you could do it is to be able to rewrite bytecode at runtime that gets increasingly tempting especially because guys like JRuby have had reasonable success of doing that but historically that's been too great a requirement to impose so we don't have that either and then and then just to make sure that it's impossible to achieve these things simultaneously binary compatibility you'll see an example of why binary compatibility is hopeless in the face of things like separate compilation so most of this what's in this talk and a hundred other things that could have gone into this talk come down to the the path from here's something we dreamed up for Scala the language and here's something we have to make work on JVM the platform the the degree to which sort of you know if your head is a little bit too far in the clouds relative to the platform you're gonna run on or if you will have an ideal in mind that it's like works great on paper it can be quite painful when you actually get down to having to make these things ago and you know it's nice we're all tempted to live in a world where just the application of intellect can solve all your problems but and many times there's so many constraints that you have been boxed into a box that you cannot unbox and I mean that literally to you when we get to boxing that's a problem so let's see an actual one okay I should I should preface this one with that quote is misattributed so but it's still such a good quote that I can't help but give it to him that's Trotsky that's correct and the actual quote of course is war except it's the actual misquote because he didn't actually say that and what he really said is you may not be interested in the the whether they call the dialect or the dial to go whatever the but the dialect is interested in you anyway so why why are things hard for us well it's a scholar the language does what is always appealing when you are looking at a mass of irregularities make it regular that does make life easier at the top so where Java has three distinct namespaces we have one where Java has basically any given thing involving primitives has to be done separately than any given thing involving references we have one model one object model where Java everything involving arrays has to be done separately in the array has to be enumerated and where we say hey all right it's just a collection a great deal of suffering is tied to that one and where Java has like well we've got primitive types but then we also have this thing void which isn't really a type it's like the absence of a type except it should have been a type because it is sort of a type and anyway we'll take void null and the absence of completion and give them put them in the type system unit no and nothing we call these to the bottom types you could have more bottom types but those are the only ones we have and yeah this sort of stands in for this for this is this is a type that has exactly one value and comically it has at various times had several forms of boxing so there's boxed unit rich unit and there was some other kind of unit going to and all of these actually turned up in mica at all trying to handle that one unit so the problem with making the irregular regular because it sounds good and it is good if you can do it the problem is you must eliminate the distinction completely you cannot get 80% of the way there 90 95 percent of the way there or you will find that there is code that takes advantage of the distinction intentionally often unintentionally often but one way or another things happen differently based on which side of that distinction things are so when you say well let's just make it so you can't even see that distinction well all of a sudden you're very double-edged sword is cutting everybody who needs to see that because there is a difference and now you've made it impossible right you've become the enemy you're standing in the way of seeing the difference and so they have a problem they can't solve because you're out there say no it doesn't matter can't see and this arises in many contexts and yes I've never never seen anybody manage to actually eliminate the distinction I mean never so here's a good one in the like stuff you just are never gonna think of up front well I say that that's not fair some people would I'd never think of this up front this one is I I can I cannot cast any aspersions on anyone for not thinking of this Java has this weird decision they made at some point maybe the best decision available to them at the time man is never supposed to be equal to nan that's like the definition of man it's like if this thing starts entering your calculations you want it to always be unequal and then somebody noticed well that means if you stick a nan key in a map you can never get it back out okay well I don't know a greatest tragedy that is but on that basis the box man is equal to the unbought to the Box nan so if you say box nan dot equals box nan it's true well so and then we walk in and say there's only one thing box nan unbox Nana's just nan well then is nan equal nan that's an actual picture of me from any point in history who mostly what you mean what it what is the answer today pretty sure that well I mean a pretty shirt acts like the primitive so we may actually get to recover the box to behavior by if if I well so I had an idea that we could define eek the reference equality thing on any so that it was available universally and if we did that then we could have eek be the boxed answer and the regular equals be the primitive answer and then we actually recover reasonable semantics that doesn't happen yet though but I sort of expect that to happen I guess it's one of the least controversial things that I have in the fire so packages so one one of the places where Scala did not go the like let's have fewer things route but let's have more things route and to a very large number is access Java has four levels of access public package which is the default protected and private and so we said let's throw a bunch more in there but one thing that is strange that is even though we threw a ton more out there we still have no way to express one of the Java ones this I'm fairly sure is not intentional but you can see that those two little examples of Java and Scala right there are to the extent that it's possible to write it in scala are the same thing but they're not the same thing in a very important way as this if you were ever to encounter it would reveal to you because in Java packages don't nest but in Scala everything nests so if you're in packaged food op bar in Scala you're also in package foo but if you're in packaged food up bar in Java you are not in packaged food you're in a completely unrelated package to packaged food so there's an example of how that gets you it is also pervaded sort of the the intersection of Java Interop trying to interoperate with Java where access is like a real thing and Scala where we have both like much more complicated access but a complete inability to encode it at the JVM level which shares Javas idea of there being exactly four levels so what we have to do is everything's public and enforce it in Scala this has issues of its own but then when you have stuff like Java calling into Scala Scala calling into Java you know that can be arbitrarily nested and then you combine it with this stuff well forget it it's bad this is a perfect example of the problem with like having more ambition in your model than your platform will support Churchill that's correct I wish he'd set it exactly this way that's so true never never never believe any feature will be smooth and easy or that anyone who embarks on the strange voyage can measure the tides and hurricanes he will encounter anybody who's attempted to have any kind of project with a timeline over a week can probably get behind that alright so here's another fun one with Java so so we say there's no we're not going to have this this huge barrier between reference types and primitive types there's there's a thing at the top it's called ne and then to the left go to any vowels that's all the primitives into the right any reps and that's all the reference types but we also interoperate with Java when we see a piece of Java code and it accepts object or type parameter are bounded by object especially what did they mean when they wrote that because maybe they really wanted to say any because they probably very likely they did it's just that object is the best they could do to say any or to write just a type parameter T with no bound expressed Java it says okay you mean T bounded by object but that's not really what they wrote that's Java being helpful say and that's all you can write in any case the question is like these things again I have written identically don't mean the same thing or maybe they don't mean the same thing we actually don't know if they mean the same thing so maybe you think why does it matter well it matters because Java makes a lot of distinctions between things or the JVM in particular makes a lot of distinctions between things and we are in on thin ice if we try to eliminate those distinctions for instance and this syntax if you haven't seen it means an array of something unknown which is a subtype of any or respectively any ref in Java you would just write array object because they're arrays are covariant unsound li we did not inherit that particular quirk but that means that if you want to say an array of something without allowing for essentially covariant behavior without it being a covariant type you have to write it like that point being that if we assume that like you know it means the one then we can do put in the byte code we can put that it's an array of objects because it's safe to say that it is but if we assume that it means an array of anything that encompasses all the primitive arrays to which don't actually share any supertype except for like serializable as somebody pointed out last time it's true it looks there see really so we could erase to serializable but the point is you can't you can no longer a race to array object if it's if it might be array any because it could be an array of int which is a very different look signature wise it's like i brackety thing instead of big old reference type ii thing point being again distinction exists if we say no no distinction then we walk into all these linkage errors at the JVM level bottom types are even worse that that method up there I'm writing a function and accepts an array of something that's a subtype of string so it thinks well what's it gonna be accepted or a string of course it's an array string it strings finals but so like how many subtypes that could possibly have well actually it's got a whole bunch now here's the trick those types subtypes a string that aren't string that they're generally speaking they're uninhabited so in if you were demanding a value of that type you would be safe because there is no value of that type that's what uninhabited means but arrays have now ten eight they'll take the uninhabited and reified is a real thing even if there's no value of that type that's a big problem that's type system death basically it means that array should never have gotten as far and being treated as like just another thing nearly as far as they have they should have been walled off and a you know like like the freakish brother and a tower somewhere and you throw food through the window but you never let him just mix with all the other collections like you're all one big happy family because you definitely not one big happy family as this example among many others will reveal the array nothing is just one possibility in Scala but again there are many many actual infinitely many types of string it's just that you can't come up with values of those types so the comment at the bottom there where there's slow motion no guys say no more bridge more bridges yeah I guess said the hour that should look better that's not how text looks on my monitor but as you can get the gist there's 34 method signatures in there implementing the same method they're all implementing seek so when you fire up a list if you go digging out all the method you know all the signatures that can be found in there that's how many can be found in there for one method and the reason there are all those is that it's got a whole bunch of parents which themselves have a bunch of parents which are refining the type as it goes down and each time you covariantly improve the return type of seek you need another bridge because the chain everything and this is as Brian likes to put it Brian gets yesterday's solutions our today's problems this was yesterday's bridge methods as being implemented by the compiler was yesterday's solution definitely today's problem because the via really has no enough that it could work this out without us having to go through this pain not to mention all the failures of correctness that we have with bridge methods this this is like the good situation where at least they all appear to be there all right so this is back to that other example again so just in case you thought that like well then don't have a nothing tight because that's the problem that's not the problem the problem is a type system that's richer than the type system around which the the java virtual machine was designed so you it just does not have a concept of this idea of like subtyping without sub classing but we have you know these intersection types you can make up anything you want it was string that's a perfectly valid type it's uninhabited but it's valid it's a real type but that's not a problem until you have this type that says well I'm gonna make that thing you know like a real part of our lives and let it propagate around and then be able to read it back in and do stuff with it and thus you that can't happen so this is the particular failure that we have right here that's our own doing right I mean what it needs to do is just erase basically every array table jecht but there's a big problem with that and that goes back to Java Interop we don't have any way to make Scala accessible from Java except method signatures and descriptors so if we erase everything down to objects all of a sudden javis like what there's nothing there I got an object and so it you're on your own casting stuff back into arrays on the job on the Java side people like what kind of interrupt is this well yeah it's not very good interrupt but we have this problem that's not really solvable so type system cannot actually be implemented in its real form we can enforce lots of stuff in Scala in principle we can like as long as you do nothing but use Scala we can make out an off a lot of stuff work because we can implement restrictions on top of the platform we don't need the platforms out but when it comes to talk in the Java we don't have that luxury and so we are constrained by what's possible which is not enough are there any questions at this point I I know people are probably not taking like a questioning move but I you know I don't know if it's too fast to slow anything so yeah I don't know why not I mean I think there should be a version of the sky like about it or anything you want I'm not real restrictive in that way but I don't know it like that would not be that would not work very well out of the box and you'd need more more sophistication applied to the problem than that but something that lets you have more control over how these things took place like whether Java interim mattered at all for instance that would be very useful oh absolutely 100% I would like if Java interrupts was of interest to me I would never just say well we'll just write it in Scala and hope that everything is cool because it never will be like you cannot have a give a it's it's very much like you know how people used to imagine they could write their program once and then compile you know like I don't know in swing or something or a WT and it'll be on all the platforms and everybody'll it there's never been a good piece of software written right that's like I got a GUI that's cross-platform right I mean I we can quibble but plus or minus we had like zero examples in history everybody wants to write a decent piece of software you know ghost does the native thing on each place this is just as true of Java and Scala more true even than it is of like Windows and Mac this this'll this'll probably be the most impressive if you know who that is he's a great thinker very worthwhile reading gets you thinking differently about programming and maybe everything else too mmm that's not a bad guess but no it's a it's a see I'm not German so I vegan Stein he has some more famous quotes among these circle things like the limits of my language of the limits of my world anyway I recommend him so this was the this originally was next to the other slide about unification because these are the places where some places a small set of places where we have expanded beyond what Java offers more access levels more parents more bottom types more xml literals more kinds of evaluation semantics that that's a little mean right there too because you know stream and views are library things but even so there are three distinct ways of encoding laziness - you know with different semantics each of them within the language then there's variants always an endless pile of joy variances beyond like variance is so useful it's like of all these things where like I look like oh god the complexity but at least variance delivers a tremendously useful payload and then of course if it wasn't enough macros but I can't really count macros when I'm like trying to slag off the language because they're experimental but they're experimental but on the other hand they've been proved useful if anybody used SBT Oh 13 oh god it's such a huge improvement and then wouldn't been possible without macros syntax like ability to manage your like basically you can just in a little build SBT you can have like you can fire off like 10 projects and have all the dependencies working everything and it's all just like like you'd like to write it not this like baroque crazy syntax right like you know let's say you've got like a property and it depends on two other things instead of having to like build up this little old function bippy you can just say like Scala version dot value and just stick it right in there and sort of like the direct syntax and it just works it translates to the other thing but you don't have to see that anymore I've been a big critic of SBT SBT Oh 13 is a huge improvement at war with the primitives I'm really bad about clocks so can somebody give me a hint like how much time I've got oh thank you all right so one of the first like major land wars in Asia that I undertook with the Scala see was trying to work make primitives do something sensible because I showed up between to seven and to eight and you know they didn't do sensible things so I was trying to bring everything together and deal with stuff like this right does one equal one well it depends on who you ask alright one equals one is one long the primitive equals one in the primitive in our language and their language but in their language as you can see one the long the box does not equal one image of the box but we don't have that distinction we need those to be equal so okay so when you write X double equals y if those things happen to be boxed not like this one happened to be because you don't know it could be anything if they happen to be boxed primitives you need to get in there before equals is called you know it's too late otherwise right so what we do is say all right if it looks like they might be then we'll get in there we'll write it differently so here is an example of what went wrong this is Scala 277 it doesn't act like this anymore the first one attempts to just compare it to things that could be anything second one compares to things that happen to be serializable 'he's chosen very specifically the the drama unfolds false how could this happen you have to remember that there was a slide about copying like many a slip twixt cup in the lip for that to make any sense there's probably too great a gap in there and you're like why is what is going on so that's that is the represents poops I spilled my coffee on the way to my mouth so what happened well if you depend on like spotting any possible scenario where they might be boxed things then you had better get it right and since serializable happens to be you know one of the super types of java.lang long and java.lang integer they could sneak in that way and the logic at the time was something along the lines of check all the box types specifically and any ref but not the types in between so and that's what I was just saying now even the success story here such as it is might be if you have performance as a thing you ever think about might be making you say what do you do you need to do that on every comparison are you guys nuts well you take one step down a road like this so the problem you have is like you got guys like me that just want to make things consistent like whatever it whatever it is you're gonna do let's just make it behave in a predictable way that's a dangerous guy to have me that guy right because that means if you got anything floating around where the logical consequence is you know some terrible end of the road well it's like you started us down that road but I'm gonna finish it no matter how bad it is and so that's a that's not always good it's bad you should did got it gotta be careful with the first step around guys like that who is what oh oh I'm sorry yeah that one is quite obscure that was John Adams not usually recognizable by picture but by name he is so of course any problem you have with equals you now have an equivalent or possibly worse in this case problem with hashcode because they've got to sort of you know I have a little shadow that goes in and out with me well so what's the hash code of one well if you ask in the dirt he says one if you ask long he says one if you ask double he says one oh seven two six nine three two four eight I so we have another dramatic reveal true whiny does equal one false still a problem now this is only a problem maybe if you're using boxed numerix as hash table keys which you're totally not supposed to do who knows what you're supposed to do in these situations right like I don't know you just discourage doing something but I mean equal objects must have equal hash codes right like that's the deal so this is again like we're getting sucked down this road so hash code became a bigger problem because we didn't have a layer of indirection we were able to intercept calls to equals by defining double equals is the thing you have to call and then saying will rewrite it before it gets to equals so people were all we didn't have such a thing for hash code ever he's calling hash code directly so it's already too late before we can get in there and rewrite hash code so if we have to come up with a different method give ourselves some interaction and then to find it around that and that's you can't see it in this font but it's it's you know whatever you call that thing sharp sharp ash cache then so that's another method that we had we had to stick on any so that there would be a variation of hash code that is like hash code except that it gives the correct answer for a some numerix of course we run right into the limits of actual possibility very quickly so it only is able to do it for the range of like shorts it's like - 32 k2 plus 32 K beyond that you're on your own okay we've run out of like physical reality has imposed I mean I'm not sure you can fit like you know double what goes to like the 307 power or something into 32-bit hashcode so weird you know we're just going to lose especially when you start looking at the Equality behavior of doubles and floats as you start moving up you'll see the claim themselves equal to you know wide ranges of other types it's a it's completely inconsistent non-transitive madness sort of equality that and then here you are trying to mimic that and forget it that's a real disassembly of what happens with these methods one of them is comparing two completely unknown things and the other is comparing Bibby's well the the logic that recognizes numerix knows that none of them are Bibby's so it's fully prepared if you are comparing pippy's to just inline the minimum extraneous logic which you may notice is still more than nothing do you know what we have to do can you see it in the fight go there when if you say x double equals YY we can't just call equals it's in opcode for there is the big one if not null if you just blindly forward two equals and you get a nullpointerexception if the left operand is null so the the logic if we know they're not numerix is equivalent to if the left operand is null then it's equal if the right operand is no otherwise call equals on the left this is then this is the failure case we're like we don't know so we're calling this is a static method call i snipped the part where it says invoke static that's a static method call sending the operands off for a long and Byzantine route through boxes runtime looking to find out what they are and and what their relationship is that's right sunsoo and there there is no part of this talk that relates to this quote has given it anyway unfortunately however it's certainly true so it's a perhaps in some future talk all right this is where we're gonna learn why we put our heads down and cry when we hear about binary compatibility now that's trait B probably that this means this is not allowed to be visible outside of this instance and it can't be visible outside of B it is literally completely inaccessible by anything according to the scholar language semantics because that's the end of B it's done nothing anywhere can possibly legally access em the two words in red I draw your attention to public that is the interface that you get if you write that trait that's the interface that X will implement that is what will be in the bytecode and that is your binary compatibility contract notice things like m and int encoded your private this inaccessible everywhere is now like in exactly the way that it is unchangeable cannot be touched without breaking binary compatibility this is the implementation class the the compilation model for traits is that they are all split into two things one is a pure interface and one is a pure just bunch of methods all the methods except as an argument the thing that implements the interface and then the code that you wrote in the trait is there in the imple class sort of with its perspective change to operate on the incoming argument instead of on self this is how multiple inheritance is dealt with so this code right here is saying okay this is the trait initializer that's called from the actual constructor of X X was the thing that implemented this that's the trait initializer if something's going to come in it's going to be a B we're gonna call this remember by the way that was not a vol that was a Val right that was a permanent never gonna change Val em even so we had to give it a setter because somehow we have to put the initial value in there so here we are calling in to the setter and passing one to set em then here is X X of course does not have what you might have imagined the field M because it can't there could be like 10 different traits that it inherited each of which has a private m and those need to all come together and the same thing they can't all be M so they have B dollar dollar m and C dollar dollar m and of course nice public getters and setters for B dollar dollar M and then look at what the constructor does it says alright let's just get the construction ball rolling and now pass ourselves off to that method over in the imple class so that it can set our private final int B dollar dollar m and since it's private we better have a setter so it can set it so we could pass ourselves over there so that it can do it if this doesn't yet seem indirect the whole picture here is we are the only ones that can see this private field but we and then when our opportunity comes to Senate we won't we'll pass ourselves off to somewhere else they will call into a different method to set it which has to exist for their benefit what it all adds up to is there's no private int rates you're dead the only place where anything can actually keep its original name is in classes which you know so essentially like if you limit yourself to single inheritance well and to stateless traits right like if you don't have if you just have methods you don't have any vowels bars or other things that involve a field somewhere then you're alright but as soon as essentially you extend beyond what the JVM and Java have agreed on then you get into this world and it's quite difficult our problems with things like incremental compilation stem in large part from this challenge because you just cannot touch anything without just this huge spin out of effect right I mean try and work on the compiler it's comical like an incremental compiler you can just go in there and just tweak a trade anywhere and because one way or another it shows up so many places everything gets recompiled one can witness this in practice quite easily and as you would into it there's the name since it was already encoded in there before probably still is and if it doesn't agree with the class as checked method error beloved read abstract method error then there the I turned into a J isn't it great that long is it J it's I guess that's my last slide so that's all that I have for you today and I'm very happy to take any questions on anything do you get the joke it's funny it's funny you'd be laughing hysterically if you got it that's what I'm gonna say I'm taking that to the grave I'm sorry no no no no god no yeah no I'm I hate I in the text editor wars I take the position that I hate them load them all with like equal passion I cannot find in like even though this this long end of this I still can't find anything I like I guess you'll see that in my later talk where I've got it like wing it on you know alive question yes well I guess I kind of have that don't I mean like in some sense nobody will use it but I'll have something all to myself I don't know I mean I dunno actually do a high degree of specificity but it doesn't really lend itself to very quick answer I would I don't know I would specify it better I would disentangle things it really it comes down to the kids there's just so many uncompelled mats at this point things where you but we're behavior has been bundled one way or another and you can't disentangle them and so you just have these unrelated concerns going all over the place we do something complicated so I would basically to the extent possible build it out of compositional blocks and prove it on the way up that's what I do but I guess we'll see what I'll do I'm trying to understand where I'm going with this basically what's what's the summary should we read in Java well I guess so if there was like I mean the real the real lesson is sort of trying to like transcend Scala and Java specifically and point out that you you're you cannot conceive of ideals no matter how good they if you do not consider what it will take to implement your ideals you know then your ideals may be deeply flawed and in fact counter to their own purpose because they may force you into places where you have to now like you know stomp on your ideals in order to get out of what you've done if you would like a more concrete thing it's probably not right in Java but in the context of Scala like these these like these issues most of these issues are plus or minus solved I mean listen not like we're like every day people are banging the door down over these these are just sort of imperfections in the process so that's that's that's as much as like there's there's no deep lesson when it comes to Scala and Java except to be aware that like like don't take too much for granted I guess yes it's but by not changing things the essential the essential way is is by not is it's a process improvement it's like okay we need to retain binary compatibility so we'll put tests in place that make sure that we do and then we'll do what we can within those constraints which are very tight and so that's why you know you look at the total amount of action in 210 and it's pretty minimal and the place where we've done anything interesting it was really difficult so it's yet another time sink you got to do these crazy gyrations to keep binary compatibility so the essential problem is unaddressed well I mean it's not if you use myma right I mean like that that's what it's for is to tell you so that like at the very least because the minimum standard here is I know that I am binary compatible right and so mine will do that for you you know there are a few little tips that can be given about like things that are sure to burn you if like if that's your interest but mostly you're in a world of trade-offs and so it's not that easy like you know traits are super useful in composing via traits is super useful and then it's very difficult to make changes after you're committed to something I I would say like the real essence of goodbye Harry compatibility is in Direction right like personally I would write my sort of interfaces in Java right and that way I know they're gonna work from Java like if that's an interest to me and then implement those interfaces and just try to keep enough layers between me and them that nothing's coming at my stuff directly then force everybody to write in terms of the interface never allow like intra talk between components and you know this requires a lot of discipline right but it's you could get a lot further than you know then you'll get naively if you took that kind of angle on things