A place to quickly share my discoveries, failures, and occasional successes as I explore the rich world of software development. My more general topic thoughts can be found at: http://blog.matthewjosephtaylor.com/
Don't wanna be here? Send us removal request.
Text
I created and released a game
https://matthewjosephtaylor.itch.io/match-3
It’s an endless match-3 puzzler with some simple physics.
It is somewhat traditional that one starts with a simple game as the first one. (though technically this is my 2nd one....lets say 1st game in the modern era).
Having now gone through this experience I will add my voice to those who recommend starting out with a simple game.
Now that that is under my belt, I’ve begun work on the next game. A single-person deck-battler game is what it is at the moment. Stay tuned for more details to come....
0 notes
Text
Thoughts on Rustlang
My raw first impressions as I read the Rust Programming Language Book https://doc.rust-lang.org/book/
I reserve...no I demand the right to change my mind later about everything below (In fact, I'll be disappointed if I don't).
These are my unfiltered musings meant for historical and entertainment purposes only (Nothing more amusing in life, than seeing how 'wrong' one's past self was) :)
Cargo
Seems to be the law of the universe that every language has its own build and dependency management system
So far seems fairly clean/simple and straight-forward
Unfortunate that creating new project also includes SCM (let one thing be responsible for one thing not 'all the things')
since I like git it is handy, but feels a bit too opinionated and bloaty
semver
will be glad when semver dies as an idea of how to link dependencies
would have preferred identifier based on content (like a hash of the source) with option to use monotonic identifier like date for convenience
lock file should absolutely be based on content-hash not a label like semver (disappointed)
Rustlang Basics
variable shadowing (dangerous?)
dangerously useful feature
could see this being labeled as 'considered harmful'
immediate impression is that the danger > usefulness but time will tell, maybe the usefulness outweighs
clear integer types (awesome)
u32 is perfect name compared to something like 'int' or 'long', etc in other languages where the important size of the integer is obscure
usize is a bit of an odd/ugly name for architecture specific size. Something like iarch would prolly have been better IMHO
WTF different behavior on debug/release mode for overflow?
Broken design
Is this being fixed/worked on?!?!?!?
why the space in specifying type like 'foo: bool'?
seems that 'bool:foo' would have been a cleaner more easily cut/pastable and easier to follow syntax design (Rust syntax seems backwards and overly expansive)
built-in tuple type (cool)
possibly 'dangerously useful'...but for the moment all I see is the sexy and want to dance with this potential danger ;)
destructuring
return multiple auto destructuring?
arrays don't auto-expand/shrink
fair trade it seems to me (for the most part data-structures should be immutable anyway).
let a: [i32; 5] is really ugly syntax
would prefer let i32:a[5] as ideal or let a: i32[5] to remain consistent with variable type specification poor syntax design choice
feels like the poor syntax of variable typing lead to the train-wreck of array-typing
let a = [3; 5]; OMFG this is now getting ridiculous
Bad design leads to worse design leads to truly evil design
first 'thing' before the semicolon is either a type or a value...wonder how many arrays have been created with the value 32 when the the type i32 was intended?
zero is the only interesting value one would want to 'autofill' an array with, and would be the expected default. This entire syntax 'feature' should go away.
At this moment going to call the variable typing syntax 'broken'. Too late to change. This will be one of the 'broken' parts of Rust that everyone has to deal with via best-practices and lint-checking. Unfortunate but here we are.
Important lesson to learn: Syntax matters for a language design. If the syntax is bad there is really no way to recover until the next language.
Nice that runtime array out-of-bounds checking is done (honestly how could it be otherwise in the modern era?)
Would be better if compiler/checker was a bit smarter and able to compile-time check OOB errors when it has the info to do so
possibly there is already a linter/checker that does this? Is there more than one?
clear distinction made between expressions and statements
difference as defined is that expressions return values and statements don't.
{} is an expression that appears to evaluate to the implicit returned value of the last expression inside of it
does that understanding hold up?
is there a return keyword? or is this how returning works?
WTF expressions are defined syntactically by missing semicolons?
Expressions do not include ending semicolons. If you add a semicolon to the end of an expression, you turn it into a statement, which will then not return a value
Immediate impression is that this is the most dodgy error-prone way of 'returning' I've every come across. Maybe it makes sense in context, and there are other safeguards that make this not as crazy as it appears on first blush...but I'm going to demand some explanation...
return is a keyword that docs say work as expected but also the return value of the function is synonymous with the value of the final expression in the block of the body of a function.
using -> to specify return type seems a bit cute for the sake of cuteness and 'being different' (extra syntax for no real purpose)
Not getting the purpose of turning an expression into a statement by adding a semicolon. At least not yet.
I'm presently thinking that the 'missing semicolon' is the way the language designers chose to be able to differentiate an expression that is meant to be evaluated and assigned to a variable within a function body, from an expression that is meant to be returned. In other words the 'missing semicolon' is effectively just a 'cute trick' to make the language look a bit different by not having a return before the last expression.
First impression is that this 'odd' syntax decision perhaps won't lead errors since the function itself should have a return type defined in the method signature. So if one accidentally puts in the semicolon like one would do for every other fucking usage of this expression (preloading my anger here in anticipation of being tricked by this constantly)) it won't cause a runtime error because the compiler should catch what I suspect is a very likely and common mistake.
They should just have mandated a return statement at the end of a function that returns a value to make things clear. Fear that the missing syntax character as replacement for a keyword is just 'being different' for no good reason that will lead to errors, where clarity of syntax would have been a touch more verbose but consistent.
I do appreciate that they wanted to have a language where the last expression evaluated to the return, and wanted to avoid the pitfall of language-users accidentally returning a thing they didn't mean to. Feel that is a common mistake in languages with 'implicit return' and the language-designers were wise to differentiate 'expressions meant for return' with 'expressions meant for assignment' but that 'missing semicolon' is an un-intuitive/un-obvious way of doing that. If they wanted to be cute I would have suggested they use -> as their return keyword and 'skipped the syntax garbage' in the method signature (like all other c-like languages have managed to avoid doing by having the return type be the thing to the left of the function-name)
First time I've run across 'arms' and 'arm' to mean something like 'execution path'. Short and simple, I think I kind of like it. A thing that needed a name. Was this innovative of Rust or already existing name I was unaware of?
No parens around conditions for if statements...hmmm....
quick check says they are allowed but give compile warning as unnecessary.
might be OK with leaving off (maybe)
Absolutely NOT OK with the compiler warning (parens in conditionals usually lead to clearifying intent of code)
eh, only seems to warn if the parens are at the top level so will back off a bit but still disagree with compiler warnings for extra-verbose syntax on general principle
quick code check on returning from conditional leads to the conclusion that one can't return from inside a condition
initial impression is that I like this behavior quite a bit.
the error message of 'unexpected token' is crap (going to be a common thing people are going to attempt to do, would be better to have compiler print more helpful message).
book gives hint to a 'match' keyword while explaining else if (excited/hopeful...please Knuth let match be what I want it to be)
Like that if is an expression. Goodbye elvis.
Randomly in playing around I've noticed that string concatenation with + isn't a thing in Rust. Hopefully there is a replacement syntax that allows string concatenation.
feel that sprintf style strings are error-prone
Like for in but don't see an equiv to for(i=0;i<10;i++). That is a really handy for-loop construct.
Range might fill 80% need for 'real' for-loop but isn't a 100% replacement
Possible that the need for this style goes away with other constructs/usage paradigms in Rust
I note that as I've gotten more into functional programming this 'old' style of for-loop is generally nicely replaced with a Range.
If all else fails hopefully creating some form of 'iterable' is easy, and perhaps that is the 'right and true' answer in all cases anyway :)
perhaps 'old school' for-loop construct is just 'dangerous by design', that seems likely given the mutated counter.
Rustlang Ownership
The string example where s1 = s2 and then s1 is referenced later which creates a compile error
WTF
Not how I expected that to behave at all, which I suppose is the point of this chapter.
I suppose intuitively I was assuming some sort of fancy 'reference counting' or that s1 and s2 would share a reference to the same underlying 'object'.
Assignment instead seems to imply 'transfer of ownership'.
First blush the fact that s1 is still 'in scope' seems to imply some sort of language syntax design problem since s1 clearly should no longer be in scope, by how the runtime expects things to behave, but is in scope as a practical matter, and how the language-user expects things to behave.
'We changed the rules of scope pray we do not change them any further' seems like an evil trick to play on the language-user.
the compile error of 'no Copy trait' is better than blowing up at runtime, and I appreciate the safety, but the real problem is that I as a language-user would not expect s1 to somehow 'internally' go out of scope
Better it seems to me that variable 'renaming' (variable to variable assignment (no expression)) be made illegal.
This also seems to imply that variables are sort of 'one time use' sort of things. Quite a different way of looking at the world. Possible that c-like syntax is just not a good fit since language-user's expect scope to behave in a way that it clearly doesn't.
Thinking that the runtime designers just made a bad choice in how to interpret the semantics of the language (hinted by the fact that docs imply that x = y will copy data from y to x instead of just let x and y share pointer to same location in memory). Seems like they want variables to mean something like 'location in memory' where really the language-user doesn't care unless the location is mutable which should be the rare case. Thinking the runtime designers hadn't quite grokked the power of immutable data structures.
Copy but no Share?
Seems that Copy 'trait' is the escape hatch to distinguish stack-level from heap-level allocation.
First impression is that all this 'Copying' is wasteful and unneeded (hoping that the Copying is a lie and that 'under the hood' immutables really do share)
All-in-all feels like at the very least the distinction between a Copy-able variable and a Drop-able variable should be visible via language syntax.
clet x = 5 and dlet y = String::from("foo")
How do I know as a language-user what is Copy and what is Drop without reading all lines of code that go into the creation of the types???
References
Well duh...why isn't this the default behavior? Pass by reference isn't a new/unexpected thing in the universe. Feels like the default being pass-by-copy is a bit old-school.
Getting feeling this is the tension between systems and application programming languages. Systems expects mutable and so wants to copy stuff all over the place to prevent the hell mutability brings, Application should in the modern era expect immutable and so expects pass-by-reference to be safe.
Thinking there is a lot of pain here that could be solved by just assuming immutable, and then treating mutable as the rare-its-ok-to-have-wierd-rules-wear-special-gloves situation
Feels like syntax around references are sort of unnecessary if one assumes pass-by-reference. Languages-users never should need the actual pointer to the memory location which was why c-like & exists. From the language-user's perspective I can't think of a legit reason why there would need to be a reason to distinguish between 'the value' and 'the reference to the value'. Just assume that the variable one has access to is a reference and move on with life, let the runtime deal with dereferencing. If it is faster for there to be a copy (simple integer value where the pointer takes just as much room as the value) let the runtime deal with that decision transparently (I don't give a !@#% what the assembly code looks like as a high-level language user, just make it do the right thing so that my assumptions of behavior are respected).
all-in-all this feels like too much ceremony for no valid reason. Just remove & as a thing. No reason for that thing to exist in a language without pointer arithmetic (oh please let there be no pointer arithmetic in Rust...).
Slices
Neat idea and useful concept
First impression is that this should just be the default mechanism for dealing with list-like data-structures. (why have a separate thing when one thing can mean both and is more powerful?)
Feels like best-practice would just to be use slices and forget the other non-slice variants exist.
Rustlang Data Structures
Structs
Goodbye sexy tuples. I'll probably still flirt with you, but you will likely be a quick-n-dirty when I'm too lazy, not for 'production' use.
interesting constructor syntax. All-in-all I think I like it on first impression.
like the 'field init shorthand syntax' alternate
love the 'other instance shorthand syntax' alternate
Tuple Structs
Dangerously useful.
Language would probably be better served without this construct, to 'gently direct' users into explicit-naming vs ordering-as-naming.
Sexy but no substance
Hopefully destructuring of Structs works as one would expect with the definition order being the value-order
Oddity just noticed playing around: String literal can't be used in place of String type? String::from("foo") != "foo". What is the type of a string literal if not String?
First introduction of annotations
@ would have been more natural than # since it is more commonly used (different just to be different again?)
Methods
'self' instead of 'this' (I can live with 'self', but hopefully there is a reasoned argument why the non-c-family name was used)
Seems like the first argument should be assumed to be &self and drop it from method signature (remove the tedium)
Feels like it wasn't done this way just to give the option of pass-by-copy, which is just sort of a bad-idea anyway (shouldn't be default, OK if hard/weird/impossible syntax for that option) in most cases.
I've been willfully ignoring the ugly that is &mut as a syntax 'keyword/symbol'. Feels like that wants to be something more like &! (lesson: symbols and keywords don't really want to be mixed together)
Enums
Do what they say on the tin (work as expected).
Like that each enum can have specific values
Like the 'helper' methods
Love the allowing of comma on last value (consistent syntax ftw)
Match
Meh on the 'optional' curly brackets.
agree it is 'noisy' syntax
that 'noise' also adds clarity
since all cases must be accounted for I think I'm more willing to trust that the additional clarity likely isn't needed
Like the 'value binding'
Up in the air on the syntax. Feels like argument-order is a bad thing to rely on.
Good that Monads like Option are 'pattern matchable'. Will be interesting to see how deep this goes(is Option just a simple enum, or something more powerful happening?).
like _ as the 'placeholder' variable name.
like () as the 'unit value' name.
not sure how to get the value of the 'wildcard' match?
like 'if let' I think
docs are kind of crap on how to use this....testing.....
Syntax seems backwards with the assignment being on the right (wtf?)
Absolutely hate the = now that I see that it means something closer to 'associate with' for if let
let foo = if let Coin::Penny = coin {... reads let foo contain the value of the result of matching Penny on the coin variable containing a Coin enum
Like the idea hate the syntax
better would be: let foo = coin if Coin::Penny {...
Starting to feel that for some reason the Rust developers are intentionally attempting to create confusing syntax on purpose (just not sure why yet)
Packages, Crates, Modules
initial impression after reading the summary: Lots of new keywords. Hopefully they are used for good purposes...but I'm reserving judgement based on some of the poor naming/syntax choices I've seen so far.
src/bin is an ugly way to to distinguish multiple 'binaries' (think they mean executables).
would prefer something like src/mains and src/lib
feel 'binary' is a bad name for a 'command line executable' and 'executable' would have been better
Modules
Like the nesting
'crate' feels a bit odd for naming choice of 'root' module. Feel name like 'root' would likely serve better
Uneasy about the 'placeholder' functions inside of module definitions.
Burdensome typing
Serves a useful purpose if modules are 'closed'
Serves a useful purpose if modules are more 'interface' in nature
first impression pathing: Like the idea and love the attention to this important detail
liking 'crate' to mean 'root module' less and less as I see the name used in the pathing....
relative pathing seems like a 'dangerously useful' idea.
Feeling that relative pathing is less useful if IDE takes on burden of refactoring...liking relative pathing less...
Like the fact there is a simple private/public (finer grained is generally less useful IMHO)
Like private as default
Like child sees parent, and children are hidden from parent
Feeling more and more as I see documentation-reasons why relative paths are used that it is always in the context of moving code around
Don't like the idea of reducing the 'strength' of module paths if it is only useful for refactoring purposes
Feels a bit like the language-designers added an unneeded/dangerous syntax element strictly to aid less-powerful code-editors
Like as as a renaming syntax
Like module file names being defined by module names
Like module hierarchies being defined by directory structure
Rustlang Collections
Happy that have, Disappointed in how the Book presents
Looking based off of the Documentation looks like better would have been to start from concepts like sequence
RE: vec![1,2,3] not sure I like a macro for Vector construction
Perhaps just a getting used to thing but construction feels like a thing I would expect Type-constructor to be able to do.
The bang I want to mean that the macro is creating a mutable thing (hopefully that is the case)
Playing around it appears that vec[1,2,3] isn't legal
would hope to construct an immutable vector
perhaps a non-sensical thing to want?
Hopefully there is an immutable sequence that takes care of what I want that to be
further evidence of poor choice on references.
Elements are typed as &i32 instead of i32
Get that that needs to be a reference, disagree that there should be a 'language-syntax' level distinction (should be a detail compiler takes care of)
unfortunate that 'panic' is an expected situation user should expect to get into
Feel using &v[100] is 'considered dangerous' and suspect shouldn't be part of language
Prefer v[100] to be an alternate syntax for v.get(100) (and then maybe just drop the more verbose form)
Once again poor language-design choices have lead to normal usage patterns being taxed with the 'uglier' form of syntax
Like the 'trick' of using enum-values for creating a 'closed-universe of types'
That is a really good trick the more I think about it.
As I think on this some more: that 'trick' I feel was worth the price of admission to learning the language and is an 'aha'.
Going to take that with me. That is a deeply good idea.
Strings
The fact that "initial contents".to_string(); is a reasonable thing to type I think speaks for itself regarding poor choices in the language.
First google on Rust String concatenation leads to an involved discussion on various ways of doing what should be a simple thing like "hello" + "world"
Going to add 'String concatenation' to my language-evaluation litmus tests
If a language can't handle the basics with grace then that is a red-flag because it is going to kill adoption-rates which is death for any language
A String is a wrapper over a Vec<u8> WTF?
How in the @#%@#% is that a reasonable way to look at Strings in the modern era?
String wants to be something like Vec<CodePoint>
Understand that in 1970 'C' can expect a String to comprised of 8-byte 'characters' but that is totally unacceptable today
Perhaps the entire built-in 'String' is just DOA?
Do people actually use this garbage in practice?
Feel there must certainly be one or (unfortunately) more libraries that people must use to handle strings in Rust if this is the built-in
&hello[0] is illegal to 'avoid confusion' but in the same breath &hello[0..1] is legal
I don't know what to say....that is just horrible
Like the attempt at guarding users from evil and just plain wrong abstraction, but the guarding is incomplete (and just proves the point that String is just broken in its current state)
I could almost accept this if this language 'evolved' from an era when ASCII was a thing. But this language started in 2010. There is just no excuse.
Thinking that current String type should be named something like C_String_WRAPPER and only be used in cases where one is interfacing with an external c-like library (and intentionally named ugly to signal the pain and torture and danger found within)
HashMaps
Hash maps also have less support from the standard library; there’s no built-in macro to construct them, for example
appears that Rust wants to treat Type construction as an 'outside' 'macro' responsibility
Don't think I agree with this philosophy
Feels like creators of Types should also be expected to be responsible for providing type-constructors
Cool with having type-construction 'open' (allowing more) but feel that there should be a basic set of constructors that cover most cases as part of the 'contract' of creating a Type.
HashMap<_, _>
Not such a fan of using _ to mean 'any' here. (feel it is fine for variables NOT for types)
It's OK and there is a consistency argument (a weak one IMHO (any != ignore))
like the more 'in your face' 'you are probably doing it wrong, are you sure?' ?
No 'literal' constructors for either Map or Sequence that I've run across. Hopefully they exist...but starting to worry...
Rustlang Errors
Distinction made between 'Recoverable' and 'Unrecoverable' errors
Wants to use Result (enum? Monad hopefully (please let enums be Monadic...getting worried they aren't)) for 'Recoverable'
Wants to use so-called panic! macro for unrecoverable.
From what I've seen so far panic is way too common and 'expected' (I've noted that array accesses can result in a 'panic')
language-users IMHO should NEVER encounter a panic in a situation that they have control over (like array accessing)
such accesses that might not have results or have errorful results should be handled in a Monadic way (return an Option or Result)
'panic' IMHO wants be reserved for truly world-ending and unexpected situations like 'out of memory' or language-runtime-bug encountered.
We are already starting off badly since I'm not a fan of the implementation of the philosophy in some of the core library stuff I've already encountered.
Possible I can still live with this as long as it is possible to intelligently and easily avoid usage of the bad/evil language 'features'
Not a fan of backtrace not being the default
Don't like that backtraces don't appear to have column-numbers (is that an option?)
Doesn't appear to be but also appears an area of active development so willing to 'wait and see' on improvement
Feel that the 'backtrace' is a bit unreadable
Disappointing that not all lines have at least line numbers
Feel that the LHS row-numbers are not useful/helpful and just add noise
Examples in the book of where/why to use panic
Get the feeling either the book-writer or language-designers never programmed anything large/complex
Possible this is just bad-writing and 'simple' examples are being used, but feel this is going to lead to bad-practices and should be noted that this is NOT the way to run a ship (just doing here for purpose of explaining this feature).
Since there is no 'warning, this is bad style' I expect that the book-writer or possibly worse the language-designers, intend users to use panic! rather freely.
Feel strongly that since the core-library uses panic freely it this reflects poor choice of the language-designers.
Feeling like panic! is possibly going to be an Achilles heel of the language depending on how poorly the language-community reacts to this bad 'usage suggestion'.
Going to have to be very careful that any libraries are conservative with panic
perhaps might even be worth an linter-check to verify that there are no panics used in library or dependencies.
Might even be so bad that panic would have to be 'caught' (if that is possible)
Don't feel that 'catching' is a good idea generally (in cases where the 'panic' is legit like OOM they shouldn't be caught)
Might be forced into that bad situation due to poor guidance by language-designers on how to use panic
Nervous that Enums and/or Results are NOT Monads
Have not seen even a hint of a map() function or that there is 'another way' / style to handling
Possibly just being uber-conservative and not wanting to be off-putting to the non-functional crowd, but I'm starting to loose faith/patience
Feeling that expect(...) is quite the poor choice of naming since it is the opposite.
else_panic! would have been a better name
OMFG they created a special syntax structure of ? to avoid 'map' ?!?!?!??
Why?
Are they intentionally being dense or is there something I'm missing?
Does ? mean map or is it just for this one special case with Result?
The ? Operator Can Only Be Used in Functions That Return Result well I guess that answers that.
At the very least they've created a special 'hard mode' way of dealing with Results...and I fear there isn't an 'easy mode'.
Chapter 13 promises 'Functional Language Features'
Feeling it is ominous that this is the 13th chapter (what horrors does it contain?)
Error Chapter contains first hints of something called a 'Trait Object' that looks like Box<dyn Error> that is supposed to 'allow for values of different types'.
In my present state of mind I don't know how much more crazy I can take before I give up.
I'm sort of 'thrilled with dread' at how bad things are going to get, and feel this new horror is looming around the corner now.
Still hopeful there is light at the end of the tunnel, and that there will be 'salvageable' parts of the language that somehow manage to save it.
At the very least it promises not to be boring which is good enough to continue....how bad can it get? :)
Books idea of 'when to call panic'
Suggests that 'unwrap' is OK to use if the 'user knows better than the compiler'
Feel this is a bad practice.
User is almost never smarter thant the compiler
Code evolves over time so what might once have been sound reasoning might no longer be sound.
Rustlang Generics/Traits
Generics appear to work as expected
Due more I feel to simple lack of imagination, or perhaps this was designed later when saner heads were in the mix.
'Monomorphization' my what a fancy word for compile-time rewriting of code to be more concrete.
Funny how some 'magic' isn't so magical under the hood.
Interesting idea to have 'paritally defined' Generics, I think I like it.
Traits == Interface
Book notes there are 'some differences' to an Interface...what are they?
Liking the 'Partial based on Type' interface implementation
Novel? First I've seen. Wonder how it feels in practice?
'Closed traits' (can't implement a 'trait' outside of your 'crate')
Appears to be targeting the 'Ruby' problem.
Agree with no 'overwriting' of external type trait impls (what killed Ruby)
Want to disagree with 'adding' traits/impls to other types.
Need to think about that some more, feel the pendulum swung a bit too far.
Feels like adding could lead to some nice behavior naming-wise and scoping-wise
pub fn notify(item: impl Summary) {
ouch that 'impl' is an ugly way to specify an interface
Why is it needed, why isn't item: Summary sufficient?
Even if it is needed that 'impl' wants do mean implimentation not interface/trait
pub fn notify<T: Summary>(item: T) {
Good to know there is an even uglier form (so I suppose one should be thankful for the slightly prettier ugly form?)
Better: pub fn notify(item : Summary) {
See no purpose currently for all the extra-special-syntax care to distinguish interfaces and types
Feels like the phrase 'coding to the interface' would be a foreign idea to the language-designer (ignorance/spite or is there a solid reason?)
The + syntax for 'combining' interfaces feels a bit lazy at first glance but 'works'
Better would be to give a proper name to a combination of interfaces
Now I see the reason for the ugly: the where clause
Feeling this fits into 'create problem so I can show how clever I am at solving the problem I just created' idiom Rust seems to be enamoured with
Better to not have the problem in the first place
pub fn notify(t : DisplayClone, u: CloneDebug) is way easier to read, type, understand
pub fn notify(t: Display + Clone, u: Clone + Debug) also works for the lazy
Just like the problem with the unneeded Reference/Value distinction, the manufactured problem of Type/Interface distinction does not benefit language-users, and in fact is a detriment.
First 'crate' and now 'impl', I'm feeling that the language-designers where big fans of the smurfs and/or brainfuck
Perhaps should feel grateful that 'crate' and 'impl' are separate (would make about as much sense to combined them)
Rustlang Lifetimes
WTF?
Why is this needed?
Surely the compiler has enough information to determine lifetimes of all references or safe defaults?
Why not just use the function scope as the lifetime (as it seems to be able to do in most cases?)?
when a function has references to or from code outside that function, it becomes almost impossible for Rust to figure out the lifetimes of the parameters or return values on its own. The lifetimes might be different each time the function is called. This is why we need to annotate the lifetimes manually. is the explanation we are given.
Why not just default to `a for lifetime of all arguments?
aka if fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { is a 'reasonable' solution why not just have the compiler write it?
Feeling like the answer is because we might be able to release some resource just a tad sooner if we give user assembly-level access to the internals of reference counter/borrower.
The real answer I fear is that the language-runtime developers sort of 'gave up' when the counter/borrower logic got too much, and left burden of their failings on the language-user, so that code could be written for some benchmark to 'prove' that Rust was just as fast/efficient as C.
IF this is a 'good' feature and not a 'BS' feature as I suspect here is a better way:
the function signature syntax itself is crap (as I've come to expect now)
Better would be fn longest(x: &[a]str, y: &[b]str) -> &[a]str {
no reason to 'define' the names ahead of usage
IMHO using square brackets makes it feel a bit more like the lifetime name is a particular 'part' of the reference (which it is, a 'time' part instead of a 'value' part)
weird apostrophe syntax is just confusing and weird, that compounds the confusion and weirdness
if one is going to do something weird at least hit the language-user with one weird thing at a time not two at once
the type syntax is crap
're-using' <> to mean either 'lifetime name' OR 'type name' has that now-familiar 'smurfy' smell to it.
better would be struct ImportantExcerpt[a] { which would allow struct ImportantExcerpt[a]<a> {
name collision between generic-type-name and lifetime-name avoided since lifetimes would only be referenced inside []
to be clear feeling rather strongly now that this is a BS language 'non-feature' but if you're going to do it, at least make the syntax not as horrible
Feel Lifetimes are now the 3rd manufactured pain-point (No reason to have except to solve its own pain)
Lol! After writing a lot of Rust code, the Rust team found that Rust programmers were entering the same lifetime annotations over and over in particular situations. These situations were predictable and followed a few deterministic patterns. The developers programmed these patterns into the compiler’s code so the borrow checker could infer the lifetimes in these situations and wouldn’t need explicit annotations.
The explanation of 'lifetime elision' admits that it isn't needed, and is due to failings of compiler to determine lifetimes (can at least commend them on honesty)
Better would be to use safe default lifetimes (I feel there is always going to be a safe option that is reasonable (function scope if nothing else))
If someone needs extra performant code then let them break out the ugly syntax in those (no doubt super rare) instances where that is needed.
Automated Tests
Well done to include automated testing as a 'built-in' for the language
Doesn't seem to be a clear distinction between 'test' source and 'production' source
Feel a simple /tests directory would have solved
Basic functionality, no real depth at all
no built-in ability co 'compose' assertion conditions
no concept of 'test resources'
Rust seems to want unit tests to live next to code
Think I can be OK with this as long as it is possible to break test code out into separate files with easily distinguishable names
Ah...there is a tests directory but is for integration testing (no access to non-public code)
Intermission chapter building a grep command
Tedious to wade through but feel it is important to get a feel for style
Better if they weren't trying to teach programming AND Rust at the same time
little chance that the audience is new to programming
Note that they use clone as a work-around for the the poor reference handling
If it is too broken to use in THE example of how to write code, then what was the point?
Shockingly, at least the book author thinks a lambda is a closure
IMHO closure is something that 'closes over' a scope (doesn't necessarily have to be a lambda but usually is)
One forms a closure and it is possible that lambdas will create a closure if they reference a scoped variable
However, if the lambda doesn't reference any scoped variables then it isn't a 'closure'
I'm frightened that the language wants to refer to lambdas a closures....please...no....
calling a lambda a closure in this way, is like calling all refrigerators 'Kenmore's
Admit to skimming here. Life is short.
Feeling that Rust is at this point language with many built-in flaws and might not be worth the effort
Will continue as the meaty subjects like concurrency and functional programming are ahead and there is still a slim chance the language isn't a total loss
It took the book author 40 paragraphs and 695 words to say: eprintln! prints to stderr. FML, my patience is wearing thin....
Rustlang Functional Features
Closures
Annoying as mentioned earlier to refer to all lambdas as closures
Feeling that this ignorant way of speaking (not using 'ignorant' in a mean way, feeling language-designer just didn't know the distinction), speaks to the ignorance of the language-designers at this point and I think hints to all the troubles this language has.
Feel the |var| {} syntax is OK but that the | is a bit of a clunky character.
Prefer var -> {} style
Telling that they mention Ruby as a inspiration choice for this syntax
Iterators
OMFG 'Iterator' has a:
map
collect
filter
Book section does a crap job of explaining or env just listing the Functional features
flatmap? : Yes https://doc.rust-lang.org/std/iter/struct.FlatMap.html
Full Iterator docs: https://doc.rust-lang.org/std/iter/index.html
Option does have a map: https://doc.rust-lang.org/std/option/enum.Option.html#method.map
Result does have a map: https://doc.rust-lang.org/rust-by-example/error/result/result_map.html
Feeling will have to look elsewhere for reasonable explanation, but happy that Rust does indeed appear to have first-class functional language features.
Faith somewhat restored
Feeling at this moment that perhaps this language is possibly salvageable if one can ignore the bad parts.
Feeling relieved (Up until I saw map on Iterator the book/language had beaten me down almost to the point of quitting)
Rustlang Documentation
Love that documentation comments can be run as tests
Feel there is a strong synergy between tests and documentation in any language
Glad Rust recognizes the synergy
Feel there is room for more here, but will give credit for a useful innovation
Meh on the ///
Would prefer an open/close style syntax at least as an option
Crate.io
Unfortunate and odd that github account is only auth mechanism (would expect to see multiple oauths)
Like the balance that 'yank' provides for publishing and 'hiding' bad-publications from view.
Feel that Semantic versioning is a mistake but an understandable one
Simple monotonic like date or 1-up integer would be better
Like the use of a publisher-secret but needs to be a signing key (maybe it is?)
Workspaces
Meh on the name, that probably wants to be something like 'Project'
No a fan of the relative paths, those want to be unique names for sub-modules
cargo install
Not a fan of 'global' 'hidden' binary installation
Better would be to have some form of built-in packager/package manager instead of going the 'hacky' way
cargo-something named binaries as 'cargo commands'
Like the naming convention and the extensibility this offers
Not a fan of 'anything ing $PATH'
Needs to be a ~/.cargo/extensions and/or project-name/.cargo/extensions
Rustlang Smart Pointers
Just reading the name I already feel like I'm going ot be sick...but let's power through....
Box puts thing on the heap
Why not just have the runtime figure out what to box/unbox?
Oh joy (not) there is a * dereferencing syntax.
At least it isn't something weird, and behaves in a c-like fashion
Going to call this the 2nd great universal mistake after 'null'
Possibly even worse, prolly Trillion-dollar instead of Billion-dollar mistake.
Deref trait
Why aren't all values 'dereferencable' ?
Hints that this isn't a real memory-pointer kind of reference/dereference like in C
Rather purposefully built-in as a control mechanism for what is on/off heap but want to make it look a bit like C
All the pain and none of the real purpose?
Why not just have a 'HeapOnly' annotation if one wants to fetishize controlling where values are stored?
Why is there a different Deref(Mut)trait for immutable / mutable?
Drop trait
Dangerously Interesting that the language gives access to when things go out of scope
Neat for logging but feels unsafe
Whole point of Rust IMHO is that it deals with resource de-allocation for the language-user
Having a destructor kind of puts a lie to the safety if language-users can fiddle with the de-allocation process too much.
Sometimes non-language resources need to be cleaned up as well, so happy to have a mechanism for indicating when this happens
Feel strongly that this should NEVER be used for language-resources (memory)
Rc trait (Reference Counter)
First impression: Dangerous to the point of probably not being recommended for use
Expect the language compiler/runtime to deal with ALL reference counting
Feels like the sort of thing that exists purely for language-users to get into trouble with it
Good debug for Rust-language compiler writers but not seeing point for language-users
Feels like this wants to be an internal-language construct that is NOT visible to normal language-users
Except possibly for debug-purposes where read-only parts like counts are exposed
RefCell
Hard to imagine a legit scenario where the compiler wasn't able to correctly reference-count
Possible this is due to lack of imagination on my part....but at the moment I don't see it.
Reference Cycles
Interesting to note that Rust does not perform any detection of reference cycles
Disappointing but that is a hard problem...something to think about
Feel that having first-level language abstractions for references only makes the cycle problem worse
Easier for language-user to have 'hidden' cycles
Rustlang Concurrency
Threads
no green threads as built-in (hints to a separate library)
move keyword to move variables
why not just move on reference?
Message Passing
Channels behave as expected
Suspect would be better threads should just create by default (result of the spawn)
Nice that Rust protects against accessing mutable variables after sending
Better if only immutable were allowed to prevent the problem
what madman would send a mutable thing and expect it to work between threads?
again feels like a 'manufactured problem' that serves no purpose
Shared Memory
Dangerous but potentially useful
Mutexes work as expected
Atomic References via Arc work as expected
Sync and Send 'marker traits'
'Build Your Own Concurrency' seems like a bad idea
I trust language-designers barely to get concurrency right, not sure if trusting a library here is a good thing
Rustlang OO
If a language must have inheritance to be an object-oriented language, then Rust is not one
Happy to see this 'non feature'
Book recommends traits (interfaces) as means for one value to have multiple 'types'
Good practice, happy it recommends
Dynamic dispatch for traits?
Why?
The compiler doesn’t know all the types that might be used with the code that is using trait objects, so it doesn’t know which method implemented on which type to call
This doesn't seem correct
'Object Safety' of 'Trait Objects'
There are no generic type parameters
WTF, why?
once you’ve used a trait object, Rust no longer knows the concrete type that’s implementing that trait
Yes it should be able to
Feels like a huge miss on the compiler, is this going to be fixed?
Interesting to note that the book spends 4351 words and 263 paragraphs explaining how one might want to implement the OO 'state pattern'
compared to 2422/173 on how to use map/collect and doesn't even mention flatmap)
Feeling the book is not using my time/attention well
Rustlang Pattern Matching
Good that matching is exhaustive
let is defined as let PATTERN = EXPRESSION;
Can't quite put my finger on it but I'm seeing let used in ways that feel inconsistent weird
if let Some(x) = some_option_value {
Why isn't this if let x: Option::Some = some_option_value; ?
Function arguments are pattern-matching in nature
fn print_coordinates(&(x, y): &(i32, i32)) {
The above wants to be:
fn print_coordinates(i32:x, i32:y) {
Another good example of how poor choices (references and bad type specification syntax) make overly syntax-garbage-filled/unreadable code.
'irrefutable' and 'refutable' to distinguish between full and partial pattern matching
Seems like reasonable language, is this a Rustism or is this widely used terminology?
Good that destructuring is a thing in Rust
Match Guards
Some(x) if x < 5 => println!("less than five: {}", x),
Really neat idea. Similar to concept in TypeScript
Would love to see this as a 'first class' definition of a type (similar to TypeScript)
| as part of match-gaurd syntax to mean 'OR'
no corresponding AND ?
Can see it getting messy, possibly less is more here
@ binding operator
Like the idea
Seems a bit too verbose
Message::Hello { id: id_variable @ 3...7 } => {
better Message::Hello::id { 3...7 } => {
and then reference the 'bound' variable to id
Rustlang Advanced Features
Trait 'placeholder' types
Why?
From reading the explanation it appears to be a hack to get round some sort of 'Generic within a Generic' combinitorial implementation issue
How often is that a thing in practice?
Is that even bad to specify the implementation multiple times?
Supertrait
Lol inheritance is bad, lets have composition via interfaces...but lets let the interfaces inherit?!?!?!
Really dumb stupid idea. You know it is wrong and do it anyway. Bad Rust, no cookie.
Newtype Pattern
Delegation to create a new wrapper type
Type aliasing
type keyword
Possibly some interesting things to be done here...will have to play around to see.
! empty type
never return
Macros
Why the need to define before use?
Get that it would make the compiler harder to write but doesn't seem like it would be that much harder
OMFG entirely different syntax
macro_rules!
Syntax appears to be very specific and limited.
Feels like more of an afterthought of 'how can we handle vargs'...oh I have an idea...kinda thing
Procedureal Macros
Ah this was what I was expecting...
Rust doesn’t have reflection capabilities
Disappointing but good to know
TLDR appears one has full control over the AST...nice!
quote! macro...that could be interesting...can use outside in 'normal' code?
WOOHOO! it works. Can use quote in 'normal' code...{maniacal laughter}
#name nice, built-in templating
Why does the limited/wierd macro_rules! form exist? (just a stop-gap/hangover?)
stringify! works as expected. Nice!
Random Thoughts (Notes I made as reading/discovering that didn't fit in chapter context)
The fact that String literals like "foo" are references is annoying
consequence of poor reference/value defaults
just forget String exists and use &str
Better if language just removed idea of reference (like 'null' the idea of a value-reference is just dangerous and bad idea that needs to die)
In those rare instances where one needs to go down to 'assembly code level' have a special syntax for that don't burden 99.99% of language-user's
Hate &str as the type name of 'String reference'. Should be &String (or they should have named the type str)
Don't like from as value Type constructor/builder. Prefer shorter of
Don't like the documentation style where mut is used in examples. Feel it encourages bad practices.
Starting to despise the word 'crate' to mean 'module' and 'library' and 'executable' where one has to construct the meaning of 'crate' via context
Feeling 'crate' is a 'smurfism'
Stunningly short-sighted to have dependencies all route through a special name like https://crates.io
What happens to all the Rust code of the world when crates.io turns evil?
Better would be to have packages identified by secure public identifier (pub-key signed) and let user's choose where to get the binary representations
How does one control artifact dependencies in Rust 'for real'? (because the default appears to be broken by design)
Love the fact that line numbers AND column numbers are specified on compile errors
Starting to feel like the reasons for the bad-choices regarding reference 'exposure' is mostly in place so designers can 'show off' the fact that the compiler will detect when the language-user does the wrong thing. Sort of like putting down stumbling-blocks intentionally just so they can 'be the hero' and show off saving the user.
Better not have the intentional stumbling-blocks IMHO
WTF? Book suggests 'asking' the compiler for the return-type of a function by 'guessing' and then looking at the compile-error
Good that the compiler does this
Bad that the book suggests this as a reasonable practice to follow
Is there no language-server for Rust?
Surely any reasonable IDE would be able to suggest type
Why isn't this in the book?
Summary and Thoughts
There a lot of things I don't like about Rust
Unexpected how many things I didn't like
So many things wrong that I suspect Rust will be a stepping-stone language
Big things Rust got wrong:
References / Pointers
I get that Rust wants to be a systems programming language but there are better and worser ways of handling the 'dirty' details.
Feel that in the rare cases where References/Pointers are needed they should be abstracted from the language-user as types not syntax
Feel that the compiler should make decisions on how the stack/heap is controlled with the user hinting (via ugly syntax) for those rare instances where language-users want more control
Lifetimes / Ownership
Happy that Rust internally does the accounting for memory/resource accounting (The big draw for the language)
Sad that they are so proud of this feature that they burden the language-user with it
Feel strongly this should be a language-runtime concept that is hidden from language-user
In general, Rust syntax is too verbose and too unnecessarily ugly for the sake of being different
Types want to be defined in a c-like 'on the left side' ('C' won, deal with it)
In general following the lead of C/C++/C#/Java/Javascript aka mainstream is preferred unless there an obvious improvement to be made
Lots of NIH renaming that doesn't serve any purpose other than to be different
Trait = Interface
Crate = Module
Workspace = Project
The Good Parts
No nulls (Awesome!)
Pattern Matching well implemented
exhaustive
destructuring
Automatic Memory/Resource accounting (sort of)
Hard to call this a 'full win' due to the ugly syntax/semantics
The next language that uses Rust as inspiration will have this without all this ugliness
'Rust without the Lifetime garbage' will be the slogan
The 'half-baked' nature of the language-user-interface is what will compel the next language into existence
Obviously people want this or Rust wouldn't exist, shame that it was implemented so imperfectly
Entirely possible that I'm being too harsh and that while the book makes a big deal of Lifetimes, in practice they are never used.
Still bad/ugly they exist as a thing, but the degree to how often language-users are confronted with this mess, is the degree to which Rust will prove to be useful
Overall
I still want to like Rust and am not discouraged enough to give up on it entirely
But I am discouraged enough to look for alternatives before I spend any significant time with it
I note that Swift is also LLVM based which should give it similarly wide reach but is geared more for Apple platforms which makes it less attractive (narrows the language-community)
Feel that most of the heavy-lifting of the language is handled by LLMV, and it might be worth-while to spend time creating the better language vs trying to ignore the bad/ugly parts of Rust
0 notes
Text
Ludum Dare Challenge Finished!
I finished my first Ludum Dare game-jam challenge!
All that you see here: https://github.com/matthewjosephtaylor/ludum-dare-38
was coded in 48hrs from scratch. I took care to document the process with screenshots and dairy-style log entries as I went along.
The game itself is...not that strong...but is playable and I crossed the finish line :) You can play the game by visiting the link.
0 notes
Text
VSCode Is Awesome, Is Microsoft Giving Up On Being Evil?
I'm typing this in VS Code.
A year or so ago I started using Atom as my light, friendly, small-footprint, general-purpose editor (for those times when using a heavy IDE like IntelliJ or Eclipse is too large a tool for the job).
I've enjoyed my time with Atom. Like any useful tool there are some things I don't like.
Written in coffeescript (A worthy language in its time but it lost, and I personally was never a fan)
Doesn't handle large files well (neither does VS Code but it has the saving grace of refusing to open large files vs lagging-to-death or crashing, which is much preferred behavior)
There are probably others but those are the ones I can think of off the top of my head, and really it is a pretty solid editor, and I wasn't actively looking for a replacement.
Then comes an interesting new fact into my life, thanks to a lunch-discussion with a co-worker.
I learned that the source code for VS Code is under the MIT license
I knew that VS Code was licensed under an 'open source' license but there are OS licenses and there are OS licenses. I had assumed that Microsoft being Microsoft that they would have chosen an OS license that would would have allowed access to the source code but would have denied forking (you can see but you can't touch). So I wrote it off as not being worth my time and attention.
I'm extremely picky on what I invest my time on. Rule of thumb: not 100% open = you have to pay me $$$ to spend time/attention on it. Closed source (including look but no touch licenses) is generally too big a risk unless there is a very large, obvious, and immediate payback.
The MIT license is well-known as perhaps the simplest, most permissive 'do what you will with the code' license available. So this new information got my attention.
Life would be simpler if evil companies would just continue to do evil things. But alas, the world it seems is not that simple.
I've been playing around with VS Code for over the weekend, and so far it is doing everything that I have asked of it.
Key bindings are simple to remap (but perhaps a tad incomplete (no 'go back to last edit' that I've been able to find so far)).
Every plugin I've wanted I've found, and they have been high-quality with recent development. The plugin 'marketplace' is an active repository with a good rating system, and easy access to source repositories.
The 'project explorer' is easily put away and recalled.
TypeScript is a language I'm actually excited to use. Long have I envied Lisp/Emacs user's ability to easily reshape their editor at will. I had thought Atom would be the editor to scratch that itch, but I think I was just too turned off by coffeescript to make a go of it. Hopefully this will be the one...
The built in terminal is amazingly good. Like open vim in it and and it behaves well good. I can see myself living in this terminal.
Haha I just figured out that it appears to be using Apple Terminal under the hood. Well played.
Tasks are powerful but weakened significantly by being project-based. Hopefully this feature request will make it through.
In the meantime the macros plugin looks kind of cool, and it might just be a that a 'better tasks' plugin already exists or might become my first plugin :)
VS Code Gotchas
There is no spell checker 'built in'. No worries, there are plugins, but one of the top plugins is not to be trusted (sends all text to a 3rd party). There is now a warning message at the top of this plugin, but the fact that it exists at all, and got so popular is worrying
Complaints
The name 'Visual Studio Code'
Too similar a name to 'Visual Studio' and 'Code' too generic so it messes up google searches (I'm currently using 'vscode' which seems to work fairly well)
The 'Visual Studio' branding is not helpful for adoption among those of us who wrote off all things Microsoft long ago which I'm sure is hindering adoption (and I very much want the tools I use to be widely adopted to get as many network effect benefits as possible).
Everything requires a restart .
Reboots are not acceptable, there is no reason why things can't be reloaded on the fly except poor programming practices.
WTF is this '.vscode' crap.
It is NOT COOL to litter up the filesystem with editor meta-data, especially without asking and making it clear this is going to happen.
Unintuitive that there are 'user settings' which I'm guessing are the global settings and 'workspace settings' which are tied to a project folder and seem to be responsible for creating the '.vscode' folder. It creates a '.vscode' merely by 'looking at' the 'workspace settings' even if no changes are made.
Themes
There needs to be a theme explorer
Should be easier/possible for me to tweak theme properties
Still a little bit evil:
Telemetry/crash reporting on by default
How to turn it off
Has Microsoft really turned the corner?
I fully admit that I had written Microsoft off many years ago. The OS was crap. The company engaged in ethically unsound practices that garnered them a well-deserved reputation as an 'evil' company. There was simply nothing about the company's actions, or philosophy that lead me to believe they were worth any brain-cells, and so I intentionally stopped paying attention to them and avoided everything they produced.
I will stand by this decision to shun that despicable organization, and I think it has served me well over the years.
But recent actions such as releasing VS Code, TypesScript and I was amazed to learn in my lunch-time conversation dotNet including the CLR Under an MIT License, including a patent promise (which is better than nothing, but is still questionable...but really the whole idea software patents is questionable, so I'm going to leave that aside for the moment), strongly suggests that Microsoft is becoming worthy of attention once again. They are even making baby-steps into turning Windows into a decent OS by adopting compatibility with Linux of all things.
Actions do speak.
While I will forever remain wary. I am, for now, no longer going to auto-ignore everything coming out of Microsoft. They have earned a cautious, untrusting, eye...but an eye all the same. :)
0 notes
Text
Docker Sandboxing Tool
Well I just spent my entire Saturday writing a tool for quickly and easily creating sandboxes in docker.
This has been something that I've wanted for a while and although I hadn't intended to devote this much time to it today...it was one of those things where I couldn't stop myself until I finished it. :)
I think I ended up creating kind of a neat tool.
https://github.com/matthewjosephtaylor/docksand
The basic premis is that the work-dir is on the host machine, and all the OS stuff is inside a docker container.
This is effectively just a nice shell script for those times when you want to do something like docker run -it --rm --entrypoint=/bin/bash image-name but want to preserve the container, mount host volumes and re-use the container.
0 notes
Text
Odd little javascript function thing
I’ve been playing a lot of screeps, which means I'm getting back into doing more serious javascript.
It's been a few years since I last did anything big with javascript ( example ) and it is nice to see that there have been a series of improvements made to the language.
'let' is my favorite new addition so far.
By accident I discovered that this works:
let obj = { doAThing() { console.log('wtf?');}} obj.doAthing(); // returns 'wtf?'
But oddly this does not work:
doAThing() { console.log('wtf?'); } // Uncaught SyntaxError: Unexpected token {
Doing a bit of googling around I can't seem to find where this new function definition mechanism was introduced, which I find odd because it is really nice.
It stops me from having to write code like this:
ojb = { doAThing: funciton doAthing() {...} }
I like to write the above code as it both names the function and gives it an object property name. Function names are nice because it allows one to include those function names in logs.
I'm reticent to use this newly discovered function definition syntax as I can't see anywhere that it is defined as legal (is it new, has it been around since forever?). I'm also bothered by the inconsistency, which makes me think that this syntax works 'by some weird accident' that I don't fully understand (though it is too useful not to be intentional). I'll update as I discover more about this odd/cool little 'quirk' of the language I've discovered, that has amused me so.
0 notes
Text
Why JEP 286 is a Bad Idea
Recently there has been a bit of talk about adding 'var' as a keyword to shortcut some of the ceremony around local variable instantiation.
This is so this:
List<String> stringList = new ArrayList<String>();
becomes this:
var stringList = new ArrayList<String>();
The full JEP is here:
http://openjdk.java.net/jeps/286
I'm in the negative camp. Here is why:
I like seeing the type on the left hand side so I can instantly discern the type rather than having to go to the method definition to find out.
var whatTypeAmI = foo.zoinc();
I don't want to spend extra thought-cycles trying to imagine or look up, or remember what the type is. When I'm reading code I want to instantly at a glance know what the type is.
Also, since there is no way to specify an interface, the var will necessarily have to be typed the same the full class.
// typed to ArrayList instead of List var num = new ArrayList();
This makes it difficult to 'code to the interface'. It is generally better to constrain the type to a narrower interface whenever possible. Use of var leads away from this core principle.
The counter argument will of course be that one isn't forced to use the new var keyword, and that it should be a 'best practice' not to use it in such instances. To which I would argue that programmers are lazy and will almost always prefer the easier path. If var exists it will be used relentlessly, whether it is 'correct' or not.
All in all I think this is a poor direction for Java to go. It is an attempt to round off some of the rough edges, but sometimes rough edges are more useful than they are annoying.
Would you rather deal with sharply cornered bolt heads or a rounded off ones, when you are tasked with disassembling an engine?
0 notes
Text
Text to UML Tools
I'm sick of using a mouse to do diagrams.
I'm a coder. I want to write some code and have a pretty diagram pop out the other end.
Googling around a bit, this appears to be the best list of current text to UML tools:
http://modeling-languages.com/uml-tools/
After looking at all of them, this is my favorite as far as ease of use and quality of the diagram produced:
https://github.com/skanaar/nomnoml
Written in javascript. Can just clone the repo, do npm install, open the index.html in your favorite browser and go.
Also an online version for the lazy and to test it out:
http://nomnoml.com/
I love the syntax, the diagrams look good, easy to use out of box, and after looking at the code, easy to understand how it works.
Unfortunatley, it really only does class diagrams (which can kind of forced to be block diagrams as well), and the 'stereotypes' that are baked in are a bit limited.
I've devoted a bit of time to extending the stereotypes, and discovered I suck at html5 canvas 2d drawing. So creating stereotypes by hand isn't going to happen, at least not easily. Plus I really, really want an interaction diagram as well.
Next new favorite I've discoverd is:
http://plantuml.com/
An online version is here:
http://www.planttext.com/planttext
A complete set of diagrams. The syntax is clean. As far as functionality goes this one has everything.
There is only one problem: The diagrams are IMHO ugly.
Under the hood plantuml appears to be creating dot files that it feeds into graphviz.
Dot it turns out is kind of a neat language.
A very neat language.
Dot itself was probably what I was looking for when I began my adventure, but plantuml on top of dot is where I would have ended up anyway since it adds the UML specific syntax.
I now have more or less what I wanted. I'm just a tad unhappy that the results are a bit rougher than I would like. Story of my life. :)
Now I just need to figure out a way to make dot graphs pretty.
Edit:
I bit the bullet and created a 'skinparam' style file that can be included so the graphs don't look quite so ugly.
https://github.com/matthewjosephtaylor/plantuml-style
(incidently, the fact that the plantuml language has local and url includes and macros is powerful...and dangerous :) )
1 note
·
View note
Text
Thoughts on Golang (Part 2)
Continuing from part one
interfaces: Feels a bit like duck typing. Very flexible. Allows one to create interfaces for already existing types which is neat. Puts more of the onus on the user of the interface vs the creator of the type, which feels a bit backwards. In effect the method signature becomes the interface. Loses some of the 'contractyness' of the concept in exchange for putting the module user more in control.
The case statement is finally useful! By getting rid of the disastrous automatic fallthrough which is how it behaved in C (and therefore many other languages) one can actually use a case statement and have it do what you think it should do, and therefore it becomes a useful language feature vs a vile pit of bugs. Aweseome!
type assertions: The syntax is a bit odd, but it works. Thanks to the sane way that case statements work, and the fact that one can switch on the type assertion, doing 'type switching' becomes a very elegant way of dealing with an unknown type. A+
go routines: Feels weird that one doesn't get a handle to the thread. In general one shouldn't need such a handle but they are nice to have at times. Perhaps there is a way to get the handles, or get a more detailed view of the runtime of the running threads I'll run into later. Bye bye thread local storage.
channels: Weird that the <- does double duty for both sending and receiving.
Panic feels very much like an exception without the ability to type the exception. Exception types often are not so helpful, so one could see it as a useful simplification. One can even simulate exception handling via use of panics and deferred resolves. I'm beginning to suspect that panic might be the cleaner way to do error handling. Just a bit odd that the 'catch' has to be at the top. Actually I think I kind of like that better anyway.
// something like a Java try/catch in go func() { defer func() { if r := recover(); r != nil { fmt.Println("recovered") } }() fmt.Println("step 1 will be called") funcThatPanics("help I need an adult!") fmt.Println("step 2 will never be called") }() fmt.Println("do i see this?, answer: yes")
Can use range on channels. Nice.
Use of <-x vs x<- to determine reader/writer is cute. Still think <- should be split into two operators. Would make this less cute, but more expressive.
The len() function feels very lispy to me for some reason. I guess because it is the primitive operation for determining the length of 'something'.
New phrase: 'goroutine leak'. When a goroutine is blocked waiting on a channel that will never be be sent to, and therefore will not garbage collected.
select as a kind of switch statement is a surprisingly clean syntax. It too uses randomness to insure that one channel doesn't hog all the attention. I'm beginning to see a pattern of intentional randomness to help a program behave in a 'statistically consistent' manor, and I approve. I haven't seen this in a language before, or at least not to this degree. Sometimes bugs hide in the crevices of how a program folds together in its runtime behavior. Randomness smooths and evens out this runtime behavior. This is a language feature that future languages should take note of.
time.Tick: Very useful function. Probably too useful. I can imagine this could be abused very easily.
labels / break to label: Dirty. Dirty. Dirty. Filthy.
Concurrency: channels appear to have some strong consistency guarantees. However, anything outside of that is wild-west territory where the language user is given an arsenal of primitives and told not to shoot themselves in the foot. Disappointing. It probably would have been a better world if goroutines were segregated from each other except via channels (perhaps something like a copy on write fork, with channels being the sole 'shared resource'). Having access to unsynchronized shared memory and telling the language user to 'use responsibly' means that go routines are much less powerful in practice than they could have been.
Example of the ugliness that arrises from weak concurrency design.
Lol. There is a -race flag to the compiler to instrument the runtime with checks for race conditions. I guess if the language makes it easy to have race conditions, then it is nice that it has a built in facility to try to detect them.
Use of blank imports for drivers: eh, feels kinda lame, but nicer than having an un 'unused' import.
Wow. Go get actually speaks scm languages like git, and does things like clone when downloading. Way cool.
'Vendor' directories: Hmmmmm.....My guess is that my opinion is going to change as I play more with the language. Initially, this seems like a very primitive way of handling dependency issues. Since there are no compiled artifacts (like jars) the source becomes how one integrates a 3rd party library. Nice in the sense that it demands one has access to the source code (which is a cannot be overstated wonderful feature), but bad in that it can get a bit unwieldy. Can't imagine right now how multiple devs would coordinate, this might get ugly...
Built in testing framework: Cool that it has one, but it is a bit on the simple side. No doubt there are many frameworks that are better, but the built in one will most likely be a good enough place to start most of the time.
Example test functions: I like. I (and I'm sure most other devlopers) routinely create 'sandbox' or 'playground' code that is used to either explain or 'play with' parts of a code base. I like that this has been formalized.
Reflection: Odd that they try to hide it like a dirty little secret. Obvious that the language designers feel this is dangerous territory.
Interesting that The Go Programming Language authors use converting Go data structures into Lisp S-Expressions as an example when discussing reflection, with no real description of what Lisp or S-Expressions are, just assuming that the reader is familiar. My suspicion is that this was at least semi-purposeful, to try to subtly make reflection seem a bit scarier than it is. A sort of gatekeeper. If you know Lisp we deem you worthy to use reflection. A bit elite-ish. It just so happens that I do know me some Lisp and am familiar with S-Expressions. So I guess I pass the test, but it is IMHO a childish game they are playing, and while I'm sure they felt they were either being clever or acting as responsible guardians, really they are just being dicks. What they should have done was use JSON since this is the modern equivalent of S-Expressions that many, many, many more people are familiar with.
Struct field tags: non-type-safe annotations. Looks like the only real way to use these is to parse them via convention. Too bad that they have to be read via reflection. Feels a bit tacked on at the last minute-ish. Useful but painful and error-prone.
Lots of 'we don't have the space to show here' in the book. A bit too much.
Unsafe: This is useful or not depending on the goal of the language. From an application development perspective: evil. From a systems programming language perspective: necessary. This is the dividing line. Since it can do unsafe stuff, Go is a systems programming language. But the goal seems to be to corral all the dangerous stuff into the unsafe package, to make it a useful application programming language as well. So how strong is that fence between the two?
Cgo: Whatever programming languages exist in a thousand years will have C bindings. Lots of details missing in the book, but the 'flavor' of how it is done seems reasonable enough. I like accessing the c types via the 'C' package, nicely done.
I find it telling that the final section of the book is a warning not to use reflection or unsafe.
Summary of thoughts to this point:
Pragmatic. I don't think anyone is going to call this language 'elegant', but there is heavy emphasis on simplicity, combined with the clear intent to try to give the language user the tools needed to get the job done. It feels very much like a refined C for the modern era, with lots of extra safety and ease of use features, like garbage collection, and pointers sans pointer arithmetic.
Things I like:
General simplicity of the language combined with a slick tool chain make it very fast to get off the ground and running.
Null/nil as a valid 'zero value' is a really nice idea that I hope more languages adopt in the future.
tuples for return values!
Finally, an example of a useable switch statement (other language designers THIS is how it should work).
Things I don't like:
int/uint based on machine word size. This deserves a loud and forceful BOO! Might be bad enough to wreck the whole language for some.
Lack of error handling facilities.
Weak mechanisms for dealing with concurrency. Channels are an excellent start, but the road ends there, with too much work left to the language user.
Things that are AWESOME:
The built in opinionated source code formatting.
Now armed with a sufficient amount of knowledge to be dangerous, I shall go forth and see what kind of Go-shaped nails need hammering. :)
0 notes
Text
Thoughts on learning Golang
My initial impetus for learning go is to get more familiar with the internals of docker, because it seems that I'm going to have to rewrite their registry service to suit my desires. Also, because learning new languages is just kind of a fun thing to do, and Go appears to have enough traction now to make it worth the effort.
Youtube video I recommend: Go Programming in One Hour
Book I'm currently reading: The Go Programming Language by Donovan & Kernighan
Here is an unordered list random thoughts as I go about the learning process:
Why does the type come after the variable name? I get the feeling this was done for no real reason other than to make it look different.
gofmt is actually pretty darn cool. I like the tabs, would have preferred the semicolons.
Pointers without pointer arithmetic. I think this is a good balance.
My first impression is that it feels a lot like C but without a lot of the accounting (memory management).
Having things like 'new' not be a keyword, and thus giving the language user the ability to shadow them seems dangerous, and I'm not sure why this was done. (At first glance I would call it a horrible design, but maybe it makes sense later on).
There doesn't seem to be a way to specify a method while defining a struct (but you can attach a method to a struct later). Perhaps there is a way of doing this but just haven't discovered yet.
I like the approach of creating small command line tools for refactoring and static analysis. Will give more lightweight editors the power one expects from a more full fledged IDE without the overhead. Very nice.
atom with the go-plus plugin works well, at least for playing around.
Channels are very unixy and I like.
Mutexes for synchronization, not so sexy.
int and uint are different depending on machine architecture == EVIL. This is a major flaw in C and I'm shocked to see the mistake repeated. This just causes lots of porting headaches for no real benefit to anyone, for relatively minor performance gain. Worse because people are going to naturally migrate to using these (because the name is short/easy/intuitive) they are going to use it by default, and be bitten. I'm just going to state that use of int/uint in golang broken by design and should never be used which is a shame. The MEANING of a type should not change based on where it is run. Utterly stupid design decision. They should have just used a name like 'word' / 'uword' for the 100 people on the planet who will actually know how to, and need to, use this type. Instead 100,000 developers are now doomed to writing 'int64' where they should have had the freedom of writing 'int' (who am I kidding? 10,000 devs will write 'int64', and 90,000 devs will use 'int' without a care or clue, until their code mysteriously breaks in weird ways depending on where it is run).
I like the name of 'rune' for a unicode code point. (does not make up for int/uint)
There is a specific 'complex32/64' type. Neat.
Immutable Strings. This seems familiar. Wonder if this was designed this way to help memory/garbage collection or for program correctness.
untyped constants: weird. Don't see the need for this. The weirdness boils down to var x = 0 being an 'int' type, and var x = 0.0 being a float64 type because the zeros are untyped constants whose values are determined as needed. So the gotcha is that var x = 0 shouldn't be used as it will default to the badly designed 'int' type.
Not sure how I feel about float64(x) as a conversion syntax. On the one hand it seems nice because it looks like a function, on the other hand it seems confusing...because it isn't really a function.
Tuples are awesome!
Using tuples for error handling is ugly! WTF? This feels like a very C-like way of error handling, and really should have been rethought. Feels like there was a disagreement on how to do error handling, and so the committee decision was to not deal with it and make it ugly for everyone. Not cool.
Enums (lack of): Should have just done it right with the type of an enum being a string value. The way they are 'suggested' to be done via struct/iota feels like a performance hack, that will serve almost no-one well over the long term.
Arrays are passed via copy rather than reference. Can pass reference via pointers. Not good or bad, just something to consider.
Slices are nice, but not being able to determine implementation of backing array could lead to not being able to use them when performance becomes critical. Definitely a case where one size isn't likely to fit all...but might fit most?
Ugly design that range's output is index, value. Should have been value, index. value is 100x more useful than index when looping, so most code is going to have _, val = range x.
No slice equality comparison via '==' like there is with array: This should be a thing. No reason not to implement it at least as a reference check, if one is going to have == mean that individual values are checked in arrays. Perhaps a good case for why '===' should be a thing, or a case why == for array shouldn't be a thing.
No set type. Disappointing.
Overall the collection types seem a bit weak. Probably libraries are expected to fill this role.
Interesting use of tuples to get around the 'null value' problem for maps. Not sure I like it, but it's interesting.
Zero values instead of nil/null : Sensible. I think I like, almost certainly I should like. But have I been drinking the poison of null values for so long that I've actually acquired a taste for them? Feels a bit limiting somehow. Like a dimension is missing. Definitely one of the better design decisions of the language (Not that the outcome is guaranteed be good, just that it is indeed different than other similar languages, and has a solid grounding on why it could be a good decision, unlike silly things like changing the order of variable name/type name), will be interesting to see how it works in practice.
Struct equality: Simplistic. I really wish there was an Equals() interface method that the equality operator would use if it found one. I'm starting to think that the comparison operators are a bit weak in general (can they be fixed via 3rd party libraries?)
Did some code experiments: Slices and Maps pass via reference, arrays pass via copy, an odd inconsistency.
Built in templating is kinda neat. Arguably not the sort of thing that should be in the core library, but perhaps useful enough to justify.
Wow, stack size grows dynamically up to 1GB. Wonder if that causes issues with recursion gone wild? Sometimes a smaller stack size can be nice, because a 1GB stack is almost certainly not going to be intended.
Named return values in the method signature are kinda neat. Especially in cases of returning a tuple I can see that as a really nice thing to have, at least as far as documentation.
Yeah, really not buying the philosophy behind error handling. Perhaps I'll be brought onboard, but for now it looks like there is some sort of irrational fear of exceptions. If they came up with something different maybe I could swallow it better, but just returning the error as another kind of data and forcing the language user into writing millions if err!=nil statements just feels draining and stupid. Like democracy, exceptions might be the worst option, except all the others, and if they couldn't think of a better idea they probably should just have swallowed their pride and used them anyway, instead of voting for no built-in error handling mechanism.
Closures. Yummy.
There seems to be several gotchas with scoping and defining variables that accidently shadow a variable in a higher scope. This could have been solved by simply making it illegal to shadow these variables by defining that only one variable of a name per scope. Why wasn't this done?
defer is a novel and interesting idea, but it feels like the real answer should be that resources should be garbage collected (closed) as soon as their 'interface object' goes out of scope. Like memory management, resource management is mostly just accounting and should be handed off to the compiler/runtime to take care of. Destructors or an optional 'Close' method interface would be a better fit.
Using defer for execution tracing is pretty nifty.
Disappointing that stack traces only have line numbers (line position is sometimes just as important), but glad that they exist.
Named receivers (naming 'this' object) : Not an immediate fan. Why was this thought to be a good idea? Seems more like a hold-over from a time when Go was being developed and they were having a fight about if the language should have objects. I've never wanted to rename 'this', seems like it would just cause confusion, and extra brain power required remembering what the 'this' object is named complexity. Yeah, just a bad idea. Going to declare that the receiver object should always be called a consistent predetermined name (I vote 'this') and that any convention that suggests otherwise is just being different for the sake of being stupid (unlike reversing the type/variable name convention which is just different purely for the sake of being different but isn't likely to cause nearly as many programming mistakes).
Seems that the style guide doesn't like you to name the receiver certain things: '"receiver name should be a reflection of its identity; don't use generic names such as "me", "this", or "self"' What a bunch of BS. Whatever you do make sure you don't call it what 99% of the OO world calls this thing. I think this fight just went from stupid to idiotic. It's one thing to allow you to call it something ugly and confusing, it is another thing entirely to officially call it 'bad style' to call it anything but what it everyone else on the planet calls it. This is going to be my goto example of where a relatively small, but bad, language design decision can get ballooned into a cult of bad practice. The idea of being different to be purposefully worse is kind of mind blowing.
Why would anyone want a non-pointer receiver? I guess it is effectively sort of like a static method, only the 'static method' has access to a copy of the receiver. I guess I can see cases where that could be useful to guarantee read-only access to the receiver object.
Implicit dereferencing feels a bit hokey and I can imagine there are cases where one is fighting the compiler, but maybe not.
Nil/Null receivers as valid objects: I think this might be genius. Allows for 'null' objects to have a well defined/meaningful state. The implementation seems more pragmatic than elegant (methods have to explicitly check for nil of the receiver object) but the idea itself is a definite 'aha' moment. This is definitely one of the golden treasures of this language to be noted and praised.
Embedding of types (especially unamed structs): An interesting way to do composition. Reminds me a bit of Ruby's mixins. Solves the multiple name collision problem by having a unique path for ambiguous names, but allows you to use the 'shortcut' short names where they are unique. Will reserve judgement. Need to see in real world practice how this gets used/abused. Definite points for creativity, and possibly a good solution to the problem.
I'm about 1/2 way through the book, haven't got to the juicy stuff like refleciton yet. So far my overall impression is that this is going to be a good language for writing small portable command line programs, and maybe other things as well, but maybe not more complex programs where the language's lack of features might start to hurt more than help. Definitely more impressed after leaning about the language, than before I started the journey.
0 notes
Text
Get Maven Artifact Version from Inside Java Runtime
Simple static method to get maven artifact version.
I was doing some build magic to get this info, but maven gives the pom.properties file for free, so why not take advantage of it?
Important that the class that is passed in is contained within the maven artifact (jar file).
private static String getMavenArtifactVersion(Class<?> clazz, String groupId, String artifactId) { Properties properties = new Properties(); try { InputStream is = clazz .getResourceAsStream("/META-INF/maven/" + groupId + "/" + artifactId + "/pom.properties"); if (is != null) { properties.load(is); } } catch (IOException e) { throw new RuntimeException(e); } return properties.getProperty("version", "UNKNOWN"); }
0 notes
Text
Release v1.0 of Java Simple Service Locator
This is basically a nicely packaged version of the code I wrote in my rant about the lack of Simple Service Locators in Java
https://github.com/matthewjosephtaylor/simple-service-locator
I’ve been using it for some home projects, and it seems to do the trick. I’ll update as I make improvements.
0 notes
Text
Thoughts on Docker: Up and Running
I just finished reading Docker: Up and Running by Karl Matthias. I'm getting to the point where I view Docker (or perhaps one of its competitors like LXD but my money is on Docker) as one of the core technologies that is going to drive the next wave of internet applications. Easily distributable lightweight containers, and infrastructure as a service are a seductive and powerful combination.
Up to this point I've been relying on the documentation from Docker's website for the majority of my knowledge. This has been a good resource, but it lacks some history, detail and vision that are better suited to book format.
Overall I'll give the book a 3.5/5.
After reading, I now know a thing or two about docker's internals and best practices that I didn't know before, which are the sort of things that are difficult to glean solely from the docs, and my main reason for reading the book. For me the later chapters, especially Chapter 8 (Debugging Containers) were the most useful. Unfortunately the early chapters didn't seem to offer much more what one would get from reading the documentation on the website. The last chapters consist of riffing off of the The 12 factor app and The Reactive Manifesto and how Docker fits into those world-views.
It's possible that I'm being a bit too harsh, and that I was really looking for something beyond what a book with the title 'up and running' was likely to provide. However, it just felt like there was a little too much filler and not enough technical punch to this book.
I have a few more Docker books lined up in my safari queue, hopefully one of them will be the Docker-bible type book I seem to be craving.
0 notes
Text
Information Acquisition
I spent the afternoon grooming my own personal collection of RSS feeds down to about 100 or so (from 200+) and plopping them into feedly as a temporary home.
I still feel the pain of Google Reader being shut down.
Since GR’s demise I have found myself more or less giving up on RSS. Like a digital hobo wandering from town to town, more and more I use sites like reddit or hackernews to filter the never-ending avalanche of information that I feel I must keep up with.
The problem with this approach is that it is a sort of one-size-fits-all solution to a problem that demands personalization. It’s like shopping at walmart for your information diet. It’s cheap and it works good enough to get by, but it is nowhere near the best one could do.
Sadly, feedly is missing the most useful feature of Google Reader: the ability to sort by the articles that were the most attention-worthy (GR had a cute name for this but it escapes me).
If only there was a service that would allow me to easily import/export my opml data and twist the knobs to sort articles by various measures of relevance, popularity, etc...
0 notes
Text
No Simple Service Locator Standard/Framework for Java?
I want to do a simple, but critical thing in Java and I’m not having a great deal of luck in finding examples of other people doing this.
What I want is a simple and hopefully standard pattern/framework/library that will let me easily locate Service Objects that I don’t plan on exposing outside of a program.
When people think SOA (Service Oriented Architecture) they immediately start thinking about networks and things like REST and WSDLs and SOAP. However, it seems that in the rush to expose services not much has been written about best practices or standards for services that are internal to a program and are explicitely not exposed.
Non-network exposed services are important too!
Martin Fowler wrote a nice article in 2004 explaining the various pros and cons of using service locators vs dependancy injection. This guy wrote an updated article in 2012 that is based on Fowler's article and gives more-or-less the state of play in the Java world today.
TLDR; Spring came along and dependancy injection sort of won the hearts and minds battle.
Fowler's words on the critical difference between Dependancy Injection and Service Locators:
The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.
A problem I have with DI (especially the annotation driven form of DI) is that it makes debugging more of a pain, that it puts a bit of magic between the developer and the runtime code.
The developer is also forced to use, understand, and cofigure a somewhat conceptually heavy framework like Spring or Guice before they can even really start coding.
I haven't played with Guice, but I know that Spring slows down program start as it scans for annotations and does its DI autowire magic. This is bad as it slows down the flow of the edit/compile/run devlopment loop.
But the main problem for me with both frameworks is lack of control I as a developer have. As a developer I want to know exactly what is happening in the lifecycle of an object, and how one object comes to know about another object. And I want to be able to discover this information by reading the code, not by reading documentation on the framework on how it conceptually works.
Anyway enough ranting on why I don't particluarly like DI.
Fowler's words on why one perhaps wouldn't want to use a service locator:
The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem.
To my mind this isn't actually a 'real' problem. This problem is caused by a lack of a standard. There should be a JSR concerning service location (and no JNDI doesn't count). There needs to be something like JSR 330 but for Service Locators. Maybe it exists and google is failing me but if it exists I haven't found it.
But that is almost beside the point.
The real real problem with both Dependancy Injection and Service Location is how to assemble stuff. How does Object A know about Service B, and how does Service B get instantiated?
With DI and JSR 330 assembly is left to the magic of the framework.
That is a huge failing as that is the important part.
Ah, but I hear you say what about OSGi?
Perhaps maybe that is the ultimate answer, but OSGi is really more about modular components than Service Location. It also comes with even more conceptual overhead and a runtime setup. If there was a standard for Service Location in java then this would probably be it. But it is a bigger monster than I want and need to have to deal with.
There is also Project Jigsaw
This has the distince disadvantage of not existing yet. From what I'm reading about it, it is Oracle's attempt to bring OSGi into the mainstream and is mostly concerned with building modules not services.
Alas, there just doesn't seem to be anything in existence that does what I want. So I've gone to the trouble to write my own. I don't like this. This is the sort of thing one uses someone else's framework or library for. But in 2015, after 20 years of development it seems that there is not a standard mechanism for doing this very basic, very simple thing.
public class ServiceLocator { public static ThreadLocal<map name="name" id="name"><div>, Object>> threadLocalServices = new ThreadLocal<map name="name"><div>, Object>>() { @Override protected Map, Object> initialValue() { return Maps.newConcurrentMap(); } }; private static Map, Object> services = Maps.newConcurrentMap(); public static T get(final Class clazz) { @SuppressWarnings("unchecked") final T object = (T) services.get(clazz); if (object == null) { throw new RuntimeException("Unable to locate service for class: " + clazz.getCanonicalName()); } return object; } public static T getThreadLocal(final Class clazz) { @SuppressWarnings("unchecked") final T object = (T) threadLocalServices.get().get(clazz); if (object == null) { throw new RuntimeException("Unable to locate service for class: " + clazz.getCanonicalName()); } return object; } public static void register(final Class clazz, final T serviceImpl) { services.put(clazz, serviceImpl); } public static void unregister(Class<?> clazz) { services.remove(clazz); } public static void registerThreadLocal(final Class clazz, final T serviceImpl) { threadLocalServices.get().put(clazz, serviceImpl); } public static void unregisterThreadLocal(Class<?> clazz) { threadLocalServices.get().remove(clazz); } private ServiceLocator() { } }
I don't claim this is perfect, and it doesn't solve the hard part of assembling the services. But it does allow one to write code like this:
@GET @Produces(MediaType.APPLICATION_JSON) public Iterable listAccounts() { return ServiceLocator.get(AccountService.class).getAccounts(); }
Addendum
After a bit more research and stumbling around I discovered to my amazement that there is a native java mechanism for Service Location: 'ServiceLoader' but nobody uses it (and I don't blame them).
Here is an IBM develperworks article appropriately titled '5 things you didn't know about ... everyday Java tools' that explains it a bit.
Long story short It is pretty close to what I want, but it's clunky and uses files in META-INF to grab implementation classes.
Then I discovered that netbeans has a 'Lookup' utility class that is a wrapper around ServiceLoader that people point to as a possibility but it seems to have the same issues that ServiceLoader does.
In the end like I said before it is the assembly part that is the hard part. I don't consider putting specially named text files with class names in them to be acceptable.
Wiring and implementation loading IMHO shouldn't be a configuration detail (either via text/xml files or annotation scanning). That needs to be a Java compiler screams at you if you get it wrong sort of thing, and so needs to live in Java code land. Text/XML config files for this sort of thing was an experiment that was tried, and failed miserably, and now we've learned the lesson and need to move on.
If I come up with what I think of as a decent Service Assembly Pattern I'll post it. For now I just have a class that looks like this:
public class ServiceAssembler { public static void assemble() { ServiceLocator.register(AccountService.class, new AccountServiceImpl()); ... }
0 notes
Text
Docker Self Signed Registry Pain
I get it that docker makes money by selling its own registry services (and hey they created a cool thing and deserve some compensation), but do they have to make it so difficult to do a self signed registry?
Problem #0
I code on a macbook pro. So I'm having to use virtualbox as a proxy. That sucks but that's life. The problem is that I use bonjour/zeroconf for name resolution. Guess what, the boot2docker image doesn't have zeroconf installed. So it took me forever to figure out that while I can't do this:
mtaylor@metis:~$ docker push fileserver.local:5000/ubuntu The push refers to a repository [fileserver.local:5000/ubuntu] (len: 1) unable to ping registry endpoint https://fileserver.local:5000/v0/ v2 ping attempt failed with error: Get https://fileserver.local:5000/v2/: dial tcp: lookup fileserver.local: no such host v1 ping attempt failed with error: Get https://fileserver.local:5000/v1/_ping: dial tcp: lookup fileserver.local: no such host
but I could do this:
mtaylor@metis:~$ curl -v -k https://fileserver.local:5000/v2/ * Trying 192.168.1.2... * Connected to fileserver.local (192.168.1.2) port 5000 (#0) * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA * Server certificate: fileserver.local > GET /v2/ HTTP/1.1 > Host: fileserver.local:5000 > User-Agent: curl/7.43.0 > Accept: */* > < HTTP/1.1 200 OK < Content-Length: 2 < Content-Type: application/json; charset=utf-8 < Docker-Distribution-Api-Version: registry/2.0 < Date: Sun, 11 Oct 2015 22:07:12 GMT < * Connection #0 to host fileserver.local left intact {}mtaylor@metis:~$
It wasn't because I had the cert wrong and it was therefore refusing to connect to the host, it was because the daemon that lives in the boot2docker virtualbox virtual machine doesn't have access to zeroconf name resolution.
Problem solved by adding an A record entry in the DNS zone file of my domain (annoying but eh, it works).
Problem #1
The real problem came when it was time to let docker know that it needed to pay attention to the CA I used to sign the registry cert (itself), or turn off checking CAs all together.
Nowhere in the !@#!%!#% documentation does it mention that when you're using virtualbox to do your dockering that all the stuff it mentions in regard to editing files int /etc/default/docker or putting your ca.crt in /etc/docker/certs.d need to be done in the virtualbox virtual machine.
In retrospect this is now obvious, now that I know the 'docker daemon' lives inside the virtual machine, and that's where all the magic happens. But being a docker newbie I naively assumed that I needed to be creating/editing those files outside of the virtual machine, since there are no other configuration tasks that require editing the configuration of the software running inside of the virtual machine.
Problem #1.5
As I became aware that I needed to modify the configuration files inside the virtual machine it then became a task of figuring out how to get root access inside of the virtualbox virtual machine docker uses (because that isn't documented in the main docs at all).
The magic commands are simple in retrospect (but this needs to be in the main documentation):
docker-machine ssh name-of-your-vm docker@name-of-your-vm:~$ sudo -s
Problem #2
It doesn't work. It's broken as of docker 1.8.2 :(
I've put my cert in the proper directory (inside the virtual machine) and still no joy. Turns out there is an open bug where the docker daemon simply refuses to read the ca.crt file.
https://github.com/docker/docker/issues/9118
However, the work around of
DOCKER_OPTS="--insecure-registry fileserver.local:5000"
inside of /etc/defaults/docker does work.
It's obviously not a perfect solution but it at least allows me to finally:
mtaylor@metis:~$ docker push fileserver.matthewjosephtaylor.com:5000/ubuntu The push refers to a repository [fileserver.matthewjosephtaylor.com:5000/ubuntu] (len: 1) cdd474520b8c: Image successfully pushed f03f3645bde1: Image successfully pushed 9302827ed0a5: Image successfully pushed 48731f0a6276: Image successfully pushed latest: digest: sha256:ce7e43866f0d66b4c9dbefca41966d60220ec4c681b2fc944dc1ca0d1d333ae1 size: 7729
and so the story has a semi-happy ending....
0 notes
Photo

An old screen shot of ‘Adaptive Poker’, a player-vs-bot poker program I wrote more than a decade ago. Shareware when that was still a thing. I didn’t strike it rich, but I sold a few copies. Oddly I sold quite a few more after someone cracked it (it had a nag screen as I recall) and posted it to a cracker forum. That day I learned that piracy is a heck of a good marketing tool. It was actually pretty good (Bot was a custom neural net that learned from the player, honing in on their weaknesses). Thinking of scrounging the source code to remake it into a webapp using Vaadin.
0 notes