From mark at twistedbanana.demon.co.uk Sun Mar 1 00:23:02 2009 From: mark at twistedbanana.demon.co.uk (Mark Mahieu) Date: Sun, 1 Mar 2009 08:23:02 +0000 Subject: Proposal: Improved Wildcard Syntax for Java In-Reply-To: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> References: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> Message-ID: On 1 Mar 2009, at 07:08, Reinier Zwitserloot wrote: > > There's also a typo in 'mneumonic' :) > > NB: For what it's worth, because the need to remember super-produces > extends-consumes does not go away, I don't think this is going to help > much. The PECS mnemonic is the other way around (http://java.sun.com/docs/ books/effective/generics.pdf). I suppose that reinforces the point this proposal is making ;) My current concern with this proposal, is that it appears to suggest migrating any and all code to use 'in/out'; although I can see how that might improve matters when applied to collection-y methods, it's less clear to me that it would be better in some other cases. For example, on the class Class we have: boolean isAnnotationPresent(Class annotationClass) which feels more obvious to me than: boolean isAnnotationPresent(Class annotationClass) To be fair, I haven't given it long to sink in. But perhaps some additional examples that don't involve the Collections API would be a good addition to this proposal? Regards, Mark From jeremy.manson at gmail.com Sun Mar 1 00:58:50 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 00:58:50 -0800 Subject: PROPOSAL: Multiline strings In-Reply-To: References: Message-ID: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> One thought springs to mind: the indentation will be weird in cases where white space matters: { StringBuilder sb = new StringBuilder(); sb.append("""in this case we need multiple lines but we can't start them with lots of whitespace"""); // ... System.err.println(sb); } Alternatively, you could have a special syntax where 4 quotes strips out leading whitespace on each line: { StringBuilder sb = new StringBuilder(); sb.append(""""select a from Area a, CountryCodes cc where cc.isoCode='UA' and a.owner = cc.country """"); } Or you could use the C++ style? { StringBuilder sb = new StringBuilder(); sb.append("select a from Area a, CountryCodes cc" "where" "cc.isoCode='UA'" "and" "a.owner = cc.country"); } Frankly, to me, the big win would actually not be multiline literals, but would be escaped String literals. I'm sick of writing all of my regexps with twice as many \ characters as they need. Jeremy On Sat, Feb 28, 2009 at 7:46 PM, wrote: > AUTHOR(s): Ruslan Shevchenko > > OVERVIEW: > ?FEATURE SUMMARY: > ? add multiline strings to java language. > ?MAJOR ADVANTAGE: > ? Possibility more elegant to write code part of codes in other languages, > ?such as sql constructions or rendering of html components. > ?MAJOR DISADVANTAGE > ? I don't know > ?ALTERNATIVES: > ?use String "+=" operator. > ?using groovy instead java in utility classes. > > EXAMPLES > > SIMPLE EXAMPLE: > > ?StringBuilder sb = new StringBuilder(); > ?sb.append("""select a from Area a, CountryCodes cc > ? ? ? ? ? ? ? ?where > ? ? ? ? ? ? ? ? ? cc.isoCode='UA' > ? ? ? ? ? ? ? ? ?and > ? ? ? ? ? ? ? ? ? a.owner = cc.country > ? ? ? ? ? ? ?"""); > ?if (question.getAreaName()!=null) { > ? ? sb.append("""and > ? ? ? ? ? ? ? ? ?a.name like ? > ? ? ? ? ? ? ? """); > ? ? sqlParams.setString(++i,question.getAreaName()); > ?} > > ?instead: > ?StringBuilder sb = new StringBuilder(); > ?sb.append("select a from Area a, CountryCodes cc\n"); > ?sb.append("where cc.isoCode='UA'\n"); > ?sb.append("and a.owner=cc.country'\n"); > ?if (question.getAreaName()!=null) { > ? ? sb.append("and a.name like ?"); > ? ? sqlParams.setString(++i,question.getAreaName()); > ?} > > > DETAILS: > ?Multiline strings are part of program text, which begin and ends > ?by three double quotes. (as in groovy and scala) Text withing such > ?brackets processed as multiline string with all rulles as normal Java > ?string literals, except it can be multiline. After parsing multiline > ?string is concatenation of lines with inserted value of system property > 'line.separator' between thems. > > > COMPILATION: > ?Multiline strings created and used in .class files exactly as ordinary > strings. > > TESTING: > ?Nothing special. add multiline strings to test-cases. > > LIBRARY SUPPORT: > ?None. > ?(May be exists sence add simple template processing to standard library, but > ?I think this is goal of next janguage iteration. Now exists many good > external > ?frameworks, such as velocity: better wait and standartize support of > winner) > > REFLECTIVE APIS: None > > OTHER CHANGES: None > > MIGRATION: None > > COMPABILITY > ?None > > REFERENCES > > ?http://bugs.sun.com/view_bug.do?bug_id=4165111 > > > > > > > > From akuhn at iam.unibe.ch Sun Mar 1 01:01:44 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 10:01:44 +0100 Subject: Use "default" keyword for default visibility. Message-ID: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR(S): Adrian Kuhn OVERVIEW Allow the "default" keyword to be used as modifier for default visibility. In strict mode, missing use of default is a warning / error, in compatibility mode both the current (ie no default keyword) and the new syntax are accepted. FEATURE SUMMARY: Use "default" keyword for default visibility. MAJOR ADVANTAGE: The missing keyword for default visibility breaks the symmetry of visibility modifiers. Since it is the only implicit modifier, omitting any of the three explicit modifiers by mistake may be the source of unexpected behavior and thus hard to track down bugs. (There was an example on a blog post recently, but I cannot find it know). MAJOR BENEFIT: Symmetry of visibility modifiers is restored. MAJOR DISADVANTAGE: Two ways to express the same thing (in compatibility mode). ALTERNATIVES: Using a comment such as /* default */ is not an alternative since such comments are not processed by the compiler. EXAMPLES public class C { default Field f; } SIMPLE EXAMPLE: See above. ADVANCED EXAMPLE: None. DETAILS SPECIFICATION: "default" is already a keyword and introducing it as a new visibility modifier is save, it does not lead to ambiguous grammar. COMPILATION: Same as now for implicit default visibility. TESTING: Same as now for implicit default visibility. LIBRARY SUPPORT: None. REFLECTIVE APIS: None. OTHER CHANGES: None. MIGRATION: Compatibility mode allows both, implicit and explicit default visibility, to be used at the same time. COMPATIBILITY BREAKING CHANGES: None. EXISTING PROGRAMS: Work fine in compatibility mode. REFERENCES EXISTING BUGS: To my best knowledge, none. URL FOR PROTOTYPE (optional): From mark at twistedbanana.demon.co.uk Sun Mar 1 01:10:18 2009 From: mark at twistedbanana.demon.co.uk (Mark Mahieu) Date: Sun, 1 Mar 2009 09:10:18 +0000 Subject: PROPOSAL: Multiline strings In-Reply-To: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> Message-ID: <1E34CF6E-6215-439A-B0AF-8EB3A4A43936@twistedbanana.demon.co.uk> On 1 Mar 2009, at 08:58, Jeremy Manson wrote: > > Frankly, to me, the big win would actually not be multiline literals, > but would be escaped String literals. I'm sick of writing all of my > regexps with twice as many \ characters as they need. > > Jeremy > Yeah :( I've seen people convert tried and tested regexes to brute force String searches using indexOf and substring rather than put up with the escaping problem. Mark From jeremy.manson at gmail.com Sun Mar 1 01:15:51 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 01:15:51 -0800 Subject: Use "default" keyword for default visibility. In-Reply-To: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> Message-ID: <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> Could you dig up the example? It is hard to see why this is compelling without it. I think it would have to be a warning instead of an error, because otherwise, it is a change that breaks backwards compatibility (i.e., it makes old stuff not compile). I think there is a reasonable sized danger in introducing so many warnings for a change this small; people are likely to ignore / get upset about the flood of warnings that their compiler is suddenly generating. Did you consider the use of annotations as an alternative? In code that I write, if something has package-private visibility, it is usually for testing; Google has a @VisibleForTesting annotation that we use. Also, why not use the package keyword? Jeremy On Sun, Mar 1, 2009 at 1:01 AM, Adrian Kuhn wrote: > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > > AUTHOR(S): Adrian Kuhn > > OVERVIEW > > Allow the "default" keyword to be used as modifier for default > visibility. In strict mode, missing use of default is a warning / > error, in compatibility mode both the current (ie no default keyword) > and the new syntax are accepted. > > FEATURE SUMMARY: Use "default" keyword for default visibility. > > MAJOR ADVANTAGE: The missing keyword for default visibility breaks the > symmetry of visibility modifiers. Since it is the only implicit > modifier, omitting any of the three explicit modifiers by mistake may > be the source of unexpected behavior and thus hard to track down bugs. > (There was an example on a blog post recently, but I cannot find it > know). > > MAJOR BENEFIT: Symmetry of visibility modifiers is restored. > > MAJOR DISADVANTAGE: Two ways to express the same thing (in > compatibility mode). > > ALTERNATIVES: Using a comment such as /* default */ is not an > alternative since such comments are not processed by the compiler. > > EXAMPLES > > public class C { > ? ? ? ?default Field f; > } > > SIMPLE EXAMPLE: See above. > > ADVANCED EXAMPLE: None. > > DETAILS > > SPECIFICATION: "default" is already a keyword and introducing it as a > new visibility modifier is save, it does not lead to ambiguous grammar. > > COMPILATION: Same as now for implicit default visibility. > > TESTING: Same as now for implicit default visibility. > > LIBRARY SUPPORT: None. > > REFLECTIVE APIS: None. > > OTHER CHANGES: None. > > MIGRATION: Compatibility mode allows both, implicit and explicit > default visibility, to be used at ?the same time. > > COMPATIBILITY > > BREAKING CHANGES: None. > > EXISTING PROGRAMS: Work fine in compatibility mode. > > REFERENCES > > EXISTING BUGS: To my best knowledge, none. > > URL FOR PROTOTYPE (optional): > > > > From mark at twistedbanana.demon.co.uk Sun Mar 1 01:29:44 2009 From: mark at twistedbanana.demon.co.uk (Mark Mahieu) Date: Sun, 1 Mar 2009 09:29:44 +0000 Subject: Use "default" keyword for default visibility. In-Reply-To: <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> Message-ID: <50D7A372-4576-4235-B3BB-C25519A85DDD@twistedbanana.demon.co.uk> Regarding use of 'package' as a modifier, Alex Buckley mentioned it as a possibility a while back on his blog, in connection to the modules JSR: http://blogs.sun.com/abuckley/en_US/entry/a_wrinkle_with_module http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4456057 I have no idea whether that's a current consideration, however. Mark On 1 Mar 2009, at 09:15, Jeremy Manson wrote: > Could you dig up the example? It is hard to see why this is > compelling without it. > > I think it would have to be a warning instead of an error, because > otherwise, it is a change that breaks backwards compatibility (i.e., > it makes old stuff not compile). I think there is a reasonable sized > danger in introducing so many warnings for a change this small; people > are likely to ignore / get upset about the flood of warnings that > their compiler is suddenly generating. > > Did you consider the use of annotations as an alternative? In code > that I write, if something has package-private visibility, it is > usually for testing; Google has a @VisibleForTesting annotation that > we use. > > Also, why not use the package keyword? > > Jeremy > > On Sun, Mar 1, 2009 at 1:01 AM, Adrian Kuhn > wrote: >> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >> >> AUTHOR(S): Adrian Kuhn >> >> OVERVIEW >> >> Allow the "default" keyword to be used as modifier for default >> visibility. In strict mode, missing use of default is a warning / >> error, in compatibility mode both the current (ie no default keyword) >> and the new syntax are accepted. >> >> FEATURE SUMMARY: Use "default" keyword for default visibility. >> >> MAJOR ADVANTAGE: The missing keyword for default visibility breaks >> the >> symmetry of visibility modifiers. Since it is the only implicit >> modifier, omitting any of the three explicit modifiers by mistake may >> be the source of unexpected behavior and thus hard to track down >> bugs. >> (There was an example on a blog post recently, but I cannot find it >> know). >> >> MAJOR BENEFIT: Symmetry of visibility modifiers is restored. >> >> MAJOR DISADVANTAGE: Two ways to express the same thing (in >> compatibility mode). >> >> ALTERNATIVES: Using a comment such as /* default */ is not an >> alternative since such comments are not processed by the compiler. >> >> EXAMPLES >> >> public class C { >> default Field f; >> } >> >> SIMPLE EXAMPLE: See above. >> >> ADVANCED EXAMPLE: None. >> >> DETAILS >> >> SPECIFICATION: "default" is already a keyword and introducing it as a >> new visibility modifier is save, it does not lead to ambiguous >> grammar. >> >> COMPILATION: Same as now for implicit default visibility. >> >> TESTING: Same as now for implicit default visibility. >> >> LIBRARY SUPPORT: None. >> >> REFLECTIVE APIS: None. >> >> OTHER CHANGES: None. >> >> MIGRATION: Compatibility mode allows both, implicit and explicit >> default visibility, to be used at the same time. >> >> COMPATIBILITY >> >> BREAKING CHANGES: None. >> >> EXISTING PROGRAMS: Work fine in compatibility mode. >> >> REFERENCES >> >> EXISTING BUGS: To my best knowledge, none. >> >> URL FOR PROTOTYPE (optional): >> >> >> >> > From jeremy.manson at gmail.com Sun Mar 1 01:32:49 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 01:32:49 -0800 Subject: Use "default" keyword for default visibility. In-Reply-To: <50D7A372-4576-4235-B3BB-C25519A85DDD@twistedbanana.demon.co.uk> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> <50D7A372-4576-4235-B3BB-C25519A85DDD@twistedbanana.demon.co.uk> Message-ID: <1631da7d0903010132h7ba08a6ep8f344ac4befcd3eb@mail.gmail.com> I can see Alex's argument. I would imagine that that belongs in the modules JSR, though. Jeremy On Sun, Mar 1, 2009 at 1:29 AM, Mark Mahieu wrote: > Regarding use of 'package' as a modifier, Alex Buckley mentioned it as a > possibility a while back on his blog, in connection to the modules JSR: > > http://blogs.sun.com/abuckley/en_US/entry/a_wrinkle_with_module > http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4456057 > > I have no idea whether that's a current consideration, however. > > Mark > > > On 1 Mar 2009, at 09:15, Jeremy Manson wrote: > >> Could you dig up the example? ?It is hard to see why this is >> compelling without it. >> >> I think it would have to be a warning instead of an error, because >> otherwise, it is a change that breaks backwards compatibility (i.e., >> it makes old stuff not compile). ?I think there is a reasonable sized >> danger in introducing so many warnings for a change this small; people >> are likely to ignore / get upset about the flood of warnings that >> their compiler is suddenly generating. >> >> Did you consider the use of annotations as an alternative? ?In code >> that I write, if something has package-private visibility, it is >> usually for testing; Google has a @VisibleForTesting annotation that >> we use. >> >> Also, why not use the package keyword? >> >> Jeremy >> >> On Sun, Mar 1, 2009 at 1:01 AM, Adrian Kuhn wrote: >>> >>> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >>> >>> AUTHOR(S): Adrian Kuhn >>> >>> OVERVIEW >>> >>> Allow the "default" keyword to be used as modifier for default >>> visibility. In strict mode, missing use of default is a warning / >>> error, in compatibility mode both the current (ie no default keyword) >>> and the new syntax are accepted. >>> >>> FEATURE SUMMARY: Use "default" keyword for default visibility. >>> >>> MAJOR ADVANTAGE: The missing keyword for default visibility breaks the >>> symmetry of visibility modifiers. Since it is the only implicit >>> modifier, omitting any of the three explicit modifiers by mistake may >>> be the source of unexpected behavior and thus hard to track down bugs. >>> (There was an example on a blog post recently, but I cannot find it >>> know). >>> >>> MAJOR BENEFIT: Symmetry of visibility modifiers is restored. >>> >>> MAJOR DISADVANTAGE: Two ways to express the same thing (in >>> compatibility mode). >>> >>> ALTERNATIVES: Using a comment such as /* default */ is not an >>> alternative since such comments are not processed by the compiler. >>> >>> EXAMPLES >>> >>> public class C { >>> ? ? ? default Field f; >>> } >>> >>> SIMPLE EXAMPLE: See above. >>> >>> ADVANCED EXAMPLE: None. >>> >>> DETAILS >>> >>> SPECIFICATION: "default" is already a keyword and introducing it as a >>> new visibility modifier is save, it does not lead to ambiguous grammar. >>> >>> COMPILATION: Same as now for implicit default visibility. >>> >>> TESTING: Same as now for implicit default visibility. >>> >>> LIBRARY SUPPORT: None. >>> >>> REFLECTIVE APIS: None. >>> >>> OTHER CHANGES: None. >>> >>> MIGRATION: Compatibility mode allows both, implicit and explicit >>> default visibility, to be used at ?the same time. >>> >>> COMPATIBILITY >>> >>> BREAKING CHANGES: None. >>> >>> EXISTING PROGRAMS: Work fine in compatibility mode. >>> >>> REFERENCES >>> >>> EXISTING BUGS: To my best knowledge, none. >>> >>> URL FOR PROTOTYPE (optional): >>> >>> >>> >>> >> > > From mark at twistedbanana.demon.co.uk Sun Mar 1 01:54:33 2009 From: mark at twistedbanana.demon.co.uk (Mark Mahieu) Date: Sun, 1 Mar 2009 09:54:33 +0000 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> Message-ID: <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> On 28 Feb 2009, at 19:08, Joshua Bloch wrote: > Neal, > > On Sat, Feb 28, 2009 at 7:41 AM, Neal Gafter wrote: > >> Josh- >> >> The compatibility section must document incompatibilities, whether or >> not you judge them likely to cause problems in practice. > > > Good point. I will add this one. And I am still interested in > whether > anyone can find some code in an existing codebase that tickles this. > Josh, The worst case I've turned up so far is the following, which would not be broken by your proposal, but I think it would be restricted in its ability to take advantage of it without further changes downstream: http://openjpa.apache.org/builds/1.2.0/apache-openjpa-1.2.0/docs/ javadoc/org/apache/openjpa/datacache/DataCacheManagerImpl.html Here, the class DataCacheManagerImpl implements two interfaces, both of which could logically be retrofitted with Disposable, but doing so would then break DataCacheManagerImpl since different type arguments would be needed (Exception and RuntimeException). (I think the idea is that an alternative implementation of DataCacheManager can be specified by the user of this library; it seems quite likely that these would extend the default DataCacheManagerImpl implementation.) Depends on how ticklish you are I guess. For me it's a hint that an interface may not be the best mechanism. Regards, Mark From akuhn at iam.unibe.ch Sun Mar 1 02:01:15 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 11:01:15 +0100 Subject: Use "default" keyword for default visibility. In-Reply-To: <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> Message-ID: On 01.03.2009, at 10:15, Jeremy Manson wrote: > Could you dig up the example? It is hard to see why this is > compelling without it. I am working on it ... to many inboxes :) > I think it would have to be a warning instead of an error, because > otherwise, it is a change that breaks backwards compatibility (i.e., > it makes old stuff not compile). I think there is a reasonable sized > danger in introducing so many warnings for a change this small; people > are likely to ignore / get upset about the flood of warnings that > their compiler is suddenly generating. > > Did you consider the use of annotations as an alternative? In code > that I write, if something has package-private visibility, it is > usually for testing; Google has a @VisibleForTesting annotation that > we use. I do, and actually use an annotation processor to reject non-annotated default visibilities. It works but feels ugly, since (at least optically) symmetry of visibility modifiers is still not given. > Also, why not use the package keyword? Wow, that's much better! However because both package and class declaration can start with package now, we might need a lookahead of two tokens in the grammar. --AA > Jeremy > > On Sun, Mar 1, 2009 at 1:01 AM, Adrian Kuhn > wrote: >> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >> >> AUTHOR(S): Adrian Kuhn >> >> OVERVIEW >> >> Allow the "default" keyword to be used as modifier for default >> visibility. In strict mode, missing use of default is a warning / >> error, in compatibility mode both the current (ie no default keyword) >> and the new syntax are accepted. >> >> FEATURE SUMMARY: Use "default" keyword for default visibility. >> >> MAJOR ADVANTAGE: The missing keyword for default visibility breaks >> the >> symmetry of visibility modifiers. Since it is the only implicit >> modifier, omitting any of the three explicit modifiers by mistake may >> be the source of unexpected behavior and thus hard to track down >> bugs. >> (There was an example on a blog post recently, but I cannot find it >> know). >> >> MAJOR BENEFIT: Symmetry of visibility modifiers is restored. >> >> MAJOR DISADVANTAGE: Two ways to express the same thing (in >> compatibility mode). >> >> ALTERNATIVES: Using a comment such as /* default */ is not an >> alternative since such comments are not processed by the compiler. >> >> EXAMPLES >> >> public class C { >> default Field f; >> } >> >> SIMPLE EXAMPLE: See above. >> >> ADVANCED EXAMPLE: None. >> >> DETAILS >> >> SPECIFICATION: "default" is already a keyword and introducing it as a >> new visibility modifier is save, it does not lead to ambiguous >> grammar. >> >> COMPILATION: Same as now for implicit default visibility. >> >> TESTING: Same as now for implicit default visibility. >> >> LIBRARY SUPPORT: None. >> >> REFLECTIVE APIS: None. >> >> OTHER CHANGES: None. >> >> MIGRATION: Compatibility mode allows both, implicit and explicit >> default visibility, to be used at the same time. >> >> COMPATIBILITY >> >> BREAKING CHANGES: None. >> >> EXISTING PROGRAMS: Work fine in compatibility mode. >> >> REFERENCES >> >> EXISTING BUGS: To my best knowledge, none. >> >> URL FOR PROTOTYPE (optional): >> >> >> >> From akuhn at iam.unibe.ch Sun Mar 1 02:20:44 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 11:20:44 +0100 Subject: Use "default" keyword for default visibility. In-Reply-To: <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> Message-ID: <6A1D1254-7506-4410-8DE2-795179B88F60@iam.unibe.ch> On 01.03.2009, at 10:15, Jeremy Manson wrote: > Could you dig up the example? It is hard to see why this is > compelling without it. http://dow.ngra.de/2009/02/16/the-ultimate-java-puzzler --AA From scolebourne at joda.org Sun Mar 1 03:44:56 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Sun, 01 Mar 2009 11:44:56 +0000 Subject: Proposal: Improved Wildcard Syntax for Java In-Reply-To: <15e8b9d20902280903h32967535l8f6e4f6580fdd93d@mail.gmail.com> References: <15e8b9d20902280903h32967535l8f6e4f6580fdd93d@mail.gmail.com> Message-ID: <49AA7538.5080302@joda.org> After some thought, I've decided I oppose this feature. The basic reasoning is that 'out' and 'in' are sufficiently more meaningful to developers to justify the complexity of a language change and supporting two ways to define the same thing. I disagree with that. (ie. I find nothing wrong with the technical aspects of the proposal/spec, other than a distaste for context sensitive keywords in general) If I see the following: public static createList(Collection coll) then I read it as: "takes a collection of Number or anything extends Number". If I see: public static sort(Comparator coll) then I read it as: "takes a comparator of Number or any superclass of Number" I personally don't find the PECS shorthand that useful. And the 'out' and 'in' keywords don't mean anything to me at all right now. Perhaps the point is whether we want to define the type (Number or anything that extends Number) or the action we can take (get stuff 'out'). I think Java is type-focussed, not action-focussed. Stephen Neal Gafter wrote: > Improved Wildcard Syntax for Java > http://docs.google.com/Doc?id=ddb3zt39_79g2mtpccz > > AUTHOR(S): > > Neal Gafter > > OVERVIEW > > The current syntax for Java's wildcards is confusing enough that > mneumonics are required to read code. We suggest adding an > alternative syntax that is much more readable, and then migrating code > to the more readable syntax over time. > > FEATURE SUMMARY: > > [Note: since this is an additional syntax for a feature already in the > language, most existing tutorial material can be used.] > > A covariant wildcard generic argument can be written either "? extends > Y" or "out Y". > > A contravariant wildcard generic argument can be written either "? > super Y" or "in Y". > > MAJOR ADVANTAGE: > > While the existing syntax is mneumonic from the point of view of > describing its effect on the type system, it is not mneumonic in its > use. The new syntax is self-mneumonic for users. > > MAJOR BENEFIT: > > Jave code that uses wildcards is more readable, as are diagnostics > involving them. > > MAJOR DISADVANTAGE: > > Two ways of doing the same thing, though we hope code will migrate > over time toward the new more readable syntax. > > ALTERNATIVES: > > None. > > EXAMPLES > > SIMPLE EXAMPLE: > > interface Collection { > boolean addAll(Collection c); > ... > } > > ADVANCED EXAMPLE: > > class Collections { > public static > void sort(List list) {...} > public static void sort(List list, Comparator c) {...} > int binarySearch(List> list, T key) {...} > public static void fill(List list, T obj) {...} > public static void copy(List dest, List src) { > ... > } > > DETAILS > > SPECIFICATION: > > "in" and "out" are added as context-sensitive keywords with precisely > the same meaning of "? super" and "? extends". As context-sensitive > keywords, they continue to be usable as identifiers in all contexts. > > COMPILATION: > > As today. > > TESTING: > > As today, though a bit of additional work to ensure that the context > sensitive keyword is handled properly by the compiler. Specifically, > that they continue to be fully usable as identifiers in other > contexts. > > LIBRARY SUPPORT: > > None. > > REFLECTIVE APIS: > > None. > > OTHER CHANGES: > > None. > > MIGRATION: > > A trivial textual substitution can be used to translate old code to > the new syntax. > > COMPATIBILITY > > BREAKING CHANGES: > > None. > > EXISTING PROGRAMS: > > No impact. > > REFERENCES > > EXISTING BUGS: > > None > > URL FOR PROTOTYPE (optional): > > None > > From scolebourne at joda.org Sun Mar 1 08:45:22 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Sun, 01 Mar 2009 16:45:22 +0000 Subject: Proposal: Elvis and Other Null-Safe Operators Message-ID: <49AABBA2.3040009@joda.org> Elvis and Other Null-Safe Operators for Java AUTHOR(S): Stephen Colebourne primarily written up by Neal Gafter (Neal Gafter is responsible for the formal write-up[6] of the proposal detailed below. However, in private communication he indicated that he did not intend to submit it to Project Coin, as indicated in his write-up: "[I do] not specifically advocate adding these features to the Java programming language. Rather, this document is offered as an example of a language change proposal in a form suitable for consideration in the JDK7 small language changes JSR. Specifically, it is more like a specification than a tutorial or sales job.". As such, this proposal is submitted by myself, thanks to Neal's willingness to allow me to reuse his write-up. For the submission, I have reworded the advantages/benefits/disadvantages/alternatives sections from Neal's original document and added detail to the examples. Please see the original[6] to compare Neal's version to mine.) *OVERVIEW* FEATURE SUMMARY: The ?: binary "Elvis" operator results in the value of the left-hand-side if it is not null, avoiding evaluation of the right-hand-side. If the left-hand-side is null, the right-hand-side is evaluated and is the result. The ?. null-safe member selection operator provides the same meaning as . (member selection), except when the left-hand-side evaluates to null, in which case any subexpressions on the right-hand-side are not evaluated and the ?. expression yields null. The ?[] indexing operator operates on a left-hand-side that is an array of object type. If the value of the left-hand operand is null, that is the result. If the left-hand-operand is not null, the index subexpression is evaluated and used to index the array, yielding the result. These three operators always result in a value, not a variable. NOTE: The Elvis operator could be added on its own without the other two operators if deemed necessary/desirable (Elvis is generally considered less controversial as far as I can tell). MAJOR ADVANTAGE: It is a common occurance in most large systems to find code that checks for null. Common cases are to provide a default value instead of null, to obtain the result from a nested JavaBean where any of the accessors might be null, or to handle auto-unboxing properly. This proposal captures these common coding patterns, and as a result makes the code clearer and more expresive. Less boilerplate. Clearer business logic. The result of /not/ handling null properly is a NullPointerException. This is such a common mistake amongst developers, that many regular internet users (non-developers) are aware of the term "NullPointerException", because of its prevalence in production systems. MAJOR BENEFIT: Two common coding patterns are simplified - defaulting the value of null, and avoiding a NPE on access. The remaining code is focussed more tightly on the business logic rather than on the details of coding. There are also significant benefits in the handling of auto-unboxing, as well as switching on enums and the for-each loop. In all three cases, the language change added an ability to create a NPE without providing an easy and obvious means to avoid it (you have to add an if statement and another level of block which entirely defeats the purpose of the 'convenience' unboxing). Finally, the proposed code will generally be slightly more performant than the code written by hand. This is because each part of the expression will only be evaluated once with the proposed change, whereas a developer will normally call each part multiple times while checking for null. MAJOR DISADVANTAGE: Associated costs in documentation, tutorials and overall language size. The principle perceived disadvantage, however, is that it encourages, rather than discourages, the use of null values in APIs. No one is disputing that empty arrays or empty collections should be returned from APIs rather than nulls, however that is only a small proportion of the returned types in any large system. Many large systems consist of large numbers of JavaBean type objects which may have null values for many of their fields (representing an absence of information, invalid data, etc.). In these cases, null is a suitable and valuable value to hold in those fields, and is widely used as such. Accessing the resulting data for use often requires defaulting the values or handling nulls, and that is where this proposal comes in. To put that another way, if you write low-level APIs, such as the JDK, Apache Commons or Google Collections, then this proposal is of little value. If your day job involves integrating code from 50 different libraries using hundreds of JavaBean style data structures where fields can all be null, then this proposal will have a huge impact. Its a matter of perspective. ALTERNATIVES: It is possible to solve some of the issues using libraries[1]. These solutions are not terribly appealing however and would be unlikely to make it into the JDK. The other alternative is, as with any proposal, to make no change. This leaves developers to continue to obscure business logic with null-handling clutter despite indicating this as their most-wanted change in Java[5]. *EXAMPLES* SIMPLE EXAMPLE: Standard example: String s = mayBeNull?.toString() ?: "null"; Auto-unboxing example: Integer ival = ...; // may be null int i = ival ?: -1; // no NPE from unboxing ADVANCED EXAMPLE: Given a Java class class Group { Person[] members; // null if no members } class Person { String name; // may be null } Group g = ...; // may be null we can compute the name of a member if the group is non-null and non-empty and the first member has a known (non-null) name, otherwise the string "nobody": final String aMember = g?.members?[0]?.name ?: "nobody"; Without this feature, a developer would currently write: String aMember = null; if (g != null && g.members != null && g.members[0].name != null) { aMember = g.members[0].name; } else { aMember = "nobody"; } The proposed version is a lot shorter, clearer, and can even be assigneed to a final variable. *DETAILS* SPECIFICATION: Lexical: We do not add any tokens to the language. Rather, we introduce new operators that are composed of a sequence of existing tokens. Syntax: The folllowing new grammar rules are added to the syntax PrimaryNoNewArray: NullSafeFieldAccess NullSafeMethodInvocation NullSafeClassInstanceCreationExpression NullSafeArrayAccess NullSafeFieldAccess: PrimaryNoNewArray ? . Identifier NullSafeMethodInvocation: PrimaryNoNewArray ? . NonWildTypeArgumentsopt Identifier ( ArgumentListopt ) NullSafeClassInstanceCreationExpression: PrimaryNoNewArray ? . new TypeArgumentsopt Identifier TypeArgumentsopt ( ArgumentListopt ) ClassBodyopt NullSafeArrayAccess: PrimaryNoNewArray ? [ Expression ] ConditionalExpression: ElvisExpression ElvisExpression: ConditionalOrExpression ? : ConditionalExpression Semantics: A null-safe field access expression e1?.name first evaluates the expression e1. If the result is null, then the null-safe field access expression's result is null. Otherwise, the result is the same as the result of the expression e1.name. In either case, the type of the result is the same as the type of e1.name. It is an error if this is not a reference type. A null-safe method invocation expression e1?.name(args) first evaluates the expression e1. If the result is null, then the null-safe method invocation expression's result is null. Otherwise the arguments are evaluated and the result is the same as the result of the invocation expression e1.name(args). In either case, the type of the result is the same as the type of e1.name(args). It is an error if this is not a reference type. A null-safe class instance creation expression e1?.new name(args) first evaluates the expression e1. If the result is null, then the null-safe class instance creation expression's result is null. Otherwise, the arguments are evaluated and the result is the same as the result of the class instance creation expression e1.new name(args). In either case, the type of the result is the same as the type of e1.new name(args). A null-safe array access expression e1?[e2] first evaluates the expression e1. If the result is null, then the null-safe array access expression's result is null. Otherwise, e2 is evaluated and the result is the same as the result of e1[e2]. In either case, the type of the result is the same as the type of e1[e2]. It is an error if this is not a reference type. An Elvis expression e1?:e2 first evaluates the expression e1. It is an error if this is not a reference type. If the result is non-null, then that is the Elvis expression's result. Otherwise, e2 is evaluated and is the result of the Elvis expression. In either case, the type of the result is the same as the type of (e1!=null)?e1:e2. [Note: this section must mention bringing the operands to a common type, for example by unboxing when e2 is a primitive, using the same rules as the ternary operator] Exception Analysis: JLS section 12.2.1 (exception analysis of expressions) is modified to read as follows. Additions are shown in bold. A method invocation expression or null-safe method invocation expression can throw an exception type E iff either: * The method to be invoked is of the form Primary.Identifier or Primary?.Identifier and the Primary expression can throw E; or * Some expression of the argument list can throw E; or * E is listed in the throws clause of the type of method that is invoked. A class instance creation expression or null-safe class instance creation expression can throw an exception type E iff either: * The expression is a qualified class instance creation expression or a null-safe class instance creation expression and the qualifying expression can throw E; or * Some expression of the argument list can throw E; or * E is listed in the throws clause of the type of the constructor that is invoked; or * The class instance creation expression or null-safe class instance creation expression includes a ClassBody, and some instnance initializer block or instance variable initializer expression in the ClassBody can throw E. For every other kind of expression, the expression can throw type E iff one of its immediate subexpressions can throw E. Definite Assignment: JLS section 16.1 (definite assignment and expressions) is augmented with the following new subsections 16.1.x Null-safe Method Invocation * v is definitely assigned after e1?.name(args) iff v is definitely assigned after e1. * v is definitely unassigned after e1?.name(args) iff v is definitely unassigned after args. * in an expression of the form e1?.name(args), v is [un]assigned before args iff v is [un]assigned after e1. 16.1.x Null-safe Class Instance Creation Expression * v is definitely assigned after e1?.new name(args) iff v is definitely assigned after e1. * v is definitely unassigned after e1?.new name(args) iff v is definitely unassigned after args. * in an expression of the form e1?.new name(args), v is [un]assigned before args iff v is [un]assigned after e1. 16.1.x Null-safe Array Access * v is definitely assigned after e1?[e2] iff v is definitely assigned after e1. * v is definitely unassigned after e1?[e2] iff v is definitely unassigned after e2. * in an expression of the form e1?[e2], v is [un]assigned before e2 iff v is [un]assigned after e1. 16.1.x Elvis Operator * v is definitely assigned after e1?:e2 iff v is definitely assigned after e1. * v is definitely unassigned after e1?:e2 iff v is definitely unassigned after e2. * in an expression of the form e1?:e2, v is [un]assigned before e2 iff v is [un]assigned after e1. COMPILATION: These new expression forms can be desugared as follows: * e1?.name is rewritten as (t != null ? t.name : null) * e1?.name(args) is rewriten as (t != null ? t.name(args) : null) * e1?.new name(args) is rewritten as (t != null ? t.new name(args) : null) * e1?[e2] is rewritten as (t != null ? t[e2] : null) * e1?:e2 is rewritten as (t != null ? t : e2) where t is a new temporary that holds the computed value of the expression e1. TESTING: This feature can be tested by exercising the various new expression forms, and verifying their correct behavior in erroneous and non-erroneous situations, with or without null as the value of the left-hand operand, and with respect to definite assignment and exception analysis. LIBRARY SUPPORT: No library support is required. REFLECTIVE APIS: No reflective APIs require any changes. However, the not-yet-public javac Tree APIs, which describe the syntactic structure of Java statements and expressions, should be augmented with new tree forms for these new expression types. OTHER CHANGES: No other platform changes are required. MIGRATION: No migration of existing code is recommended. These new language features are mainly to be used in new code. However, IDEs should provide refactoring advice for taking advantage of these new operators when existing code uses the corresponding idiom. *COMPATIBILITY* BREAKING CHANGES: No breaking changes are caused by this proposal. EXISTING PROGRAMS: Because the changes are purely the introduction of new expression forms, there is no impact on the meaning of existing code. *REFERENCES* EXISTING BUGS: 4151957: Proposal: null-safe field access operator URL FOR PROTOTYPE: No Java prototype exists at this time. However, Groovy[2] and Fan[3] (among others) have the Elvis and null-safe member operators. OTHER REFERENCES [1] Stephan Schmidt's discussion of Better Strategies for Null Handling in Java - http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java [2] Groovy Operators - http://groovy.codehaus.org/Operators [3] Fan operators - http://fandev.org/doc/docLang/Expressions.html#nullConvenience [4] Stephen Colebourne's brief on null-safe operators - http://docs.google.com/View?docid=dfn5297z_3c73gwb [5] Summary of three recent language change polls showing better null handling as a key developer request - http://www.jroller.com/scolebourne/entry/jdk_7_language_changes_everyone [6] The version of this proposal written by Neal Gafter - http://docs.google.com/Doc?docid=ddb3zt39_78frdf87dc&hl=en From neal at gafter.com Sun Mar 1 09:05:20 2009 From: neal at gafter.com (Neal Gafter) Date: Sun, 1 Mar 2009 09:05:20 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <49AABBA2.3040009@joda.org> References: <49AABBA2.3040009@joda.org> Message-ID: <15e8b9d20903010905h79c15eb4vad4cc4ed7af7bc05@mail.gmail.com> Stephen- One small nit: In the aMember example of how things have to be done today, the variable aMember could be declared as a blank final. Regards, Neal On Sun, Mar 1, 2009 at 8:45 AM, Stephen Colebourne wrote: > Elvis and Other Null-Safe Operators for Java > AUTHOR(S): > Stephen Colebourne > primarily written up by Neal Gafter > > (Neal Gafter is responsible for the formal write-up[6] of the proposal > detailed below. However, in private communication he indicated that he > did not intend to submit it to Project Coin, as indicated in his > write-up: "[I do] not specifically advocate adding these features to the > Java programming language. ?Rather, this document is offered as an > example of a language change proposal in a form suitable for > consideration in the JDK7 small language changes JSR. ?Specifically, it > is more like a specification than a tutorial or sales job.". > > As such, this proposal is submitted by myself, thanks to Neal's > willingness to allow me to reuse his write-up. For the submission, I > have reworded the advantages/benefits/disadvantages/alternatives > sections from Neal's original document and added detail to the examples. > Please see the original[6] to compare Neal's version to mine.) > > > *OVERVIEW* > > FEATURE SUMMARY: > The ?: binary "Elvis" operator results in the value of the > left-hand-side if it is not null, avoiding evaluation of the > right-hand-side. ?If the left-hand-side is null, the right-hand-side is > evaluated and is the result. > > The ?. null-safe member selection operator provides the same meaning as > . (member selection), except when the left-hand-side evaluates to null, > in which case any subexpressions on the right-hand-side are not > evaluated and the ?. expression yields null. > > The ?[] indexing operator operates on a left-hand-side that is an array > of object type. ?If the value of the left-hand operand is null, that is > the result. ?If the left-hand-operand is not null, the index > subexpression is evaluated and used to index the array, yielding the result. > These three operators always result in a value, not a variable. > > NOTE: The Elvis operator could be added on its own without the other two > operators if deemed necessary/desirable (Elvis is generally considered > less controversial as far as I can tell). > > MAJOR ADVANTAGE: > It is a common occurance in most large systems to find code that checks > for null. Common cases are to provide a default value instead of null, > to obtain the result from a nested JavaBean where any of the accessors > might be null, or to handle auto-unboxing properly. This proposal > captures these common coding patterns, and as a result makes the code > clearer and more expresive. Less boilerplate. Clearer business logic. > > The result of /not/ handling null properly is a NullPointerException. > This is such a common mistake amongst developers, that many regular > internet users (non-developers) are aware of the term > "NullPointerException", because of its prevalence in production systems. > > MAJOR BENEFIT: > Two common coding patterns are simplified - defaulting the value of > null, and avoiding a NPE on access. The remaining code is focussed more > tightly on the business logic rather than on the details of coding. > > There are also significant benefits in the handling of auto-unboxing, as > well as switching on enums and the for-each loop. In all three cases, > the language change added an ability to create a NPE without providing > an easy and obvious means to avoid it (you have to add an if statement > and another level of block which entirely defeats the purpose of the > 'convenience' unboxing). > > Finally, the proposed code will generally be slightly more performant > than the code written by hand. This is because each part of the > expression will only be evaluated once with the proposed change, whereas > a developer will normally call each part multiple times while checking > for null. > > MAJOR DISADVANTAGE: > Associated costs in documentation, tutorials and overall language size. > > The principle perceived disadvantage, however, is that it encourages, > rather than discourages, the use of null values in APIs. No one is > disputing that empty arrays or empty collections should be returned from > APIs rather than nulls, however that is only a small proportion of the > returned types in any large system. Many large systems consist of large > numbers of JavaBean type objects which may have null values for many of > their fields (representing an absence of information, invalid data, > etc.). In these cases, null is a suitable and valuable value to hold in > those fields, and is widely used as such. Accessing the resulting data > for use often requires defaulting the values or handling nulls, and that > is where this proposal comes in. > > To put that another way, if you write low-level APIs, such as the JDK, > Apache Commons or Google Collections, then this proposal is of little > value. If your day job involves integrating code from 50 different > libraries using hundreds of JavaBean style data structures where fields > can all be null, then this proposal will have a huge impact. Its a > matter of perspective. > > ALTERNATIVES: > It is possible to solve some of the issues using libraries[1]. These > solutions are not terribly appealing however and would be unlikely to > make it into the JDK. > > The other alternative is, as with any proposal, to make no change. This > leaves developers to continue to obscure business logic with > null-handling clutter despite indicating this as their most-wanted > change in Java[5]. > > > *EXAMPLES* > > SIMPLE EXAMPLE: > Standard example: > ?String s = mayBeNull?.toString() ?: "null"; > > Auto-unboxing example: > ?Integer ival = ...; ?// may be null > ?int i = ival ?: -1; ?// no NPE from unboxing > > ADVANCED EXAMPLE: > Given a Java class > > class Group { > ? Person[] members; // null if no members > } > class Person { > ? ?String name; // may be null > } > Group g = ...; // may be null > > we can compute the name of a member if the group is non-null and > non-empty and the first member has a known (non-null) name, otherwise > the string "nobody": > > ?final String aMember = g?.members?[0]?.name ?: "nobody"; > > Without this feature, a developer would currently write: > > ?String aMember = null; > ?if (g != null && g.members != null && g.members[0].name != null) { > ? ?aMember = g.members[0].name; > ?} else { > ? ?aMember = "nobody"; > ?} > > The proposed version is a lot shorter, clearer, and can even be > assigneed to a final variable. > > > *DETAILS* > > SPECIFICATION: > Lexical: > > We do not add any tokens to the language. ?Rather, we introduce new > operators that are composed of a sequence of existing tokens. > > Syntax: > > The folllowing new grammar rules are added to the syntax > > PrimaryNoNewArray: > > NullSafeFieldAccess > NullSafeMethodInvocation > NullSafeClassInstanceCreationExpression > NullSafeArrayAccess > > NullSafeFieldAccess: > > PrimaryNoNewArray ? . Identifier > > NullSafeMethodInvocation: > > PrimaryNoNewArray ? . NonWildTypeArgumentsopt Identifier ( ArgumentListopt ) > > NullSafeClassInstanceCreationExpression: > > PrimaryNoNewArray ? . new TypeArgumentsopt Identifier TypeArgumentsopt ( > ArgumentListopt ) ClassBodyopt > > NullSafeArrayAccess: > > PrimaryNoNewArray ? [ Expression ] > > ConditionalExpression: > > ElvisExpression > > ElvisExpression: > > ConditionalOrExpression ? : ConditionalExpression > > Semantics: > > A null-safe field access expression e1?.name first evaluates the > expression e1. ?If the result is null, then the null-safe field access > expression's result is null. ?Otherwise, the result is the same as the > result of the expression e1.name. ?In either case, the type of the > result is the same as the type of e1.name. ?It is an error if this is > not a reference type. > > A null-safe method invocation expression e1?.name(args) first evaluates > the expression e1. ?If the result is null, then the null-safe method > invocation expression's result is null. ?Otherwise the arguments are > evaluated and the result is the same as the result of the invocation > expression e1.name(args). ?In either case, the type of the result is the > same as the type of e1.name(args). ?It is an error if this is not a > reference type. > > A null-safe class instance creation expression e1?.new name(args) first > evaluates the expression e1. ?If the result is null, then the null-safe > class instance creation expression's result is null. ?Otherwise, the > arguments are evaluated and the result is the same as the result of the > class instance creation expression e1.new name(args). ?In either case, > the type of the result is the same as the type of e1.new name(args). > > A null-safe array access expression e1?[e2] first evaluates the > expression e1. ?If the result is null, then the null-safe array access > expression's result is null. ?Otherwise, e2 is evaluated and the result > is the same as the result of e1[e2]. ?In either case, the type of the > result is the same as the type of e1[e2]. ?It is an error if this is not > a reference type. > > An Elvis expression e1?:e2 first evaluates the expression e1. ?It is an > error if this is not a reference type. ?If the result is non-null, then > that is the Elvis expression's result. ?Otherwise, e2 is evaluated and > is the result of the Elvis expression. ?In either case, the type of the > result is the same as the type of (e1!=null)?e1:e2. ?[Note: this section > must mention bringing the operands to a common type, for example by > unboxing when e2 is a primitive, using the same rules as the ternary > operator] > > Exception Analysis: > > JLS section 12.2.1 (exception analysis of expressions) is modified to > read as follows. ?Additions are shown in bold. > > A method invocation expression or null-safe method invocation expression > can throw an exception type E iff either: > > ? ? * The method to be invoked is of the form Primary.Identifier or > Primary?.Identifier and the Primary expression can throw E; or > ? ? * Some expression of the argument list can throw E; or > ? ? * E is listed in the throws clause of the type of method that is > invoked. > > A class instance creation expression or null-safe class instance > creation expression can throw an exception type E iff either: > > ? ? * The expression is a qualified class instance creation expression > or a null-safe class instance creation expression and the qualifying > expression can throw E; or > ? ? * Some expression of the argument list can throw E; or > ? ? * E is listed in the throws clause of the type of the constructor > that is invoked; or > ? ? * The class instance creation expression or null-safe class > instance creation expression includes a ClassBody, and some instnance > initializer block or instance variable initializer expression in the > ClassBody can throw E. > > For every other kind of expression, the expression can throw type E iff > one of its immediate subexpressions can throw E. > > Definite Assignment: > > JLS section 16.1 (definite assignment and expressions) is augmented with > the following new subsections > > 16.1.x Null-safe Method Invocation > > ? ? * v is definitely assigned after e1?.name(args) iff v is definitely > assigned after e1. > ? ? * v is definitely unassigned after e1?.name(args) iff v is > definitely unassigned after args. > ? ? * in an expression of the form e1?.name(args), v is [un]assigned > before args iff v is [un]assigned after e1. > > > 16.1.x Null-safe Class Instance Creation Expression > > ? ? * v is definitely assigned after e1?.new name(args) iff v is > definitely assigned after e1. > ? ? * v is definitely unassigned after e1?.new name(args) iff v is > definitely unassigned after args. > ? ? * in an expression of the form e1?.new name(args), v is > [un]assigned before args iff v is [un]assigned after e1. > > > 16.1.x Null-safe Array Access > > ? ? * v is definitely assigned after e1?[e2] iff v is definitely > assigned after e1. > ? ? * v is definitely unassigned after e1?[e2] iff v is definitely > unassigned after e2. > ? ? * in an expression of the form e1?[e2], v is [un]assigned before e2 > iff v is [un]assigned after e1. > > > 16.1.x Elvis Operator > > ? ? * v is definitely assigned after e1?:e2 iff v is definitely > assigned after e1. > ? ? * v is definitely unassigned after e1?:e2 iff v is definitely > unassigned after e2. > ? ? * in an expression of the form e1?:e2, v is [un]assigned before e2 > iff v is [un]assigned after e1. > > COMPILATION: > These new expression forms can be desugared as follows: > > ? ? * e1?.name is rewritten as (t != null ? t.name : null) > ? ? * e1?.name(args) is rewriten as (t != null ? t.name(args) : null) > ? ? * e1?.new name(args) is rewritten as (t != null ? t.new name(args) > : null) > ? ? * e1?[e2] is rewritten as (t != null ? t[e2] : null) > ? ? * e1?:e2 is rewritten as (t != null ? t : e2) > > > where t is a new temporary that holds the computed value of the > expression e1. > > TESTING: > This feature can be tested by exercising the various new expression > forms, and verifying their correct behavior in erroneous and > non-erroneous situations, with or without null as the value of the > left-hand operand, and with respect to definite assignment and exception > analysis. > > LIBRARY SUPPORT: > No library support is required. > > REFLECTIVE APIS: > No reflective APIs require any changes. ?However, the not-yet-public > javac Tree APIs, which describe the syntactic structure of Java > statements and expressions, should be augmented with new tree forms for > these new expression types. > > OTHER CHANGES: > No other platform changes are required. > > MIGRATION: > No migration of existing code is recommended. ?These new language > features are mainly to be used in new code. ?However, IDEs should > provide refactoring advice for taking advantage of these new operators > when existing code uses the corresponding idiom. > > > *COMPATIBILITY* > > BREAKING CHANGES: > No breaking changes are caused by this proposal. > > EXISTING PROGRAMS: > Because the changes are purely the introduction of new expression forms, > there is no impact on the meaning of existing code. > > > *REFERENCES* > > EXISTING BUGS: > 4151957: Proposal: null-safe field access operator > > URL FOR PROTOTYPE: > No Java prototype exists at this time. ?However, Groovy[2] and Fan[3] > (among others) have the Elvis and null-safe member operators. > > OTHER REFERENCES > [1] Stephan Schmidt's discussion of Better Strategies for Null Handling > in Java - > http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java > [2] Groovy Operators - http://groovy.codehaus.org/Operators > [3] Fan operators - > http://fandev.org/doc/docLang/Expressions.html#nullConvenience > [4] Stephen Colebourne's brief on null-safe operators - > http://docs.google.com/View?docid=dfn5297z_3c73gwb > [5] Summary of three recent language change polls showing better null > handling as a key developer request - > http://www.jroller.com/scolebourne/entry/jdk_7_language_changes_everyone > [6] The version of this proposal written by Neal Gafter - > http://docs.google.com/Doc?docid=ddb3zt39_78frdf87dc&hl=en > > > From jeremy.manson at gmail.com Sun Mar 1 09:07:23 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 09:07:23 -0800 Subject: Use "default" keyword for default visibility. In-Reply-To: <6A1D1254-7506-4410-8DE2-795179B88F60@iam.unibe.ch> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> <6A1D1254-7506-4410-8DE2-795179B88F60@iam.unibe.ch> Message-ID: <1631da7d0903010907p2b3d0fd5nb03dca435608742e@mail.gmail.com> I'm not sure that I understand how using a package qualifier would actually help anyone's intuition in this case. You still get the same behavior. If you are getting the behavior anyway, the only people who would be helped by putting in an explicit package qualifier are those who already understand the existing override semantics. Those are the people who likely wouldn't have this problem in the first place. No? It is also worth pointing out that using the existing @Override annotation does, in fact, cover many of the cases that concern the author of this puzzler. Jeremy On Sun, Mar 1, 2009 at 2:20 AM, Adrian Kuhn wrote: > On 01.03.2009, at 10:15, Jeremy Manson wrote: > >> Could you dig up the example? ?It is hard to see why this is >> compelling without it. > > http://dow.ngra.de/2009/02/16/the-ultimate-java-puzzler > > --AA > From akuhn at gmx.ch Sun Mar 1 01:16:57 2009 From: akuhn at gmx.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 10:16:57 +0100 Subject: PROPOSAL: Multiline strings In-Reply-To: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> Message-ID: <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> On 01.03.2009, at 09:58, Jeremy Manson wrote: > Frankly, to me, the big win would actually not be multiline literals, > but would be escaped String literals. I'm sick of writing all of my > regexps with twice as many \ characters as they need. In this case, why not allow regexps to be written literally in source code? As is done in many other languages. Although, this change would couple the regexp API with the language. But maybe here, the benefit might be worth the costs. --AA From jeremy.manson at gmail.com Sun Mar 1 09:48:53 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 09:48:53 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <49AABBA2.3040009@joda.org> References: <49AABBA2.3040009@joda.org> Message-ID: <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> > The principle perceived disadvantage, however, is that it encourages, > rather than discourages, the use of null values in APIs. I would think that the principle disadvantage would be not that it encourages use of null values (which, as you point out, is fine in some contexts), but that it encourages programmers not to think about what happens when there is a null value. I can easily imagine programmers using this all of the time without thinking about it, and then being surprised when a null ends up in the wrong place and not knowing how it got there. Even with a simple example: public String someFunction(String a, String b) { String s = a?.concat("foo"); String t = b?.concat(a); return myHashMap?.get(t); } Now, someFunction returns null. Is it because a was null? Or b was null? Or myHashMap was null? Or there was no mapping for t in myHashMap? I then imagine this spread out over 70 methods and 10,000 LOC, and realize that problems will be much harder to track down. In short, the danger is that lazy programmers start using this construct when getting a null value actually matters. I'd much rather stick with fail-fast NPEs for this case. If you want to cut down on extraneous if-testing, I would use JSR-305's Nullity annotations instead. Jeremy From jeremy.manson at gmail.com Sun Mar 1 09:53:35 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 09:53:35 -0800 Subject: PROPOSAL: Multiline strings In-Reply-To: <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> Message-ID: <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> The plus side of the escaped String approach is that you can then use any language, not just regexps. Also, escaped Strings might be a plus for security purposes. Also, I'm not a big fan of the idea of embedding the domain-specific-language-du-jour into my programming language. I see it as a slippery slope. It's regexps today, but it's XML tomorrow (I'm looking at you, Scala). Jeremy On Sun, Mar 1, 2009 at 1:16 AM, Adrian Kuhn wrote: > On 01.03.2009, at 09:58, Jeremy Manson wrote: > >> Frankly, to me, the big win would actually not be multiline literals, >> but would be escaped String literals. ?I'm sick of writing all of my >> regexps with twice as many \ characters as they need. > > In this case, why not allow regexps to be written literally in source > code? As is done in many other languages. Although, this change would > couple the regexp API with the language. But maybe here, the benefit > might be worth the costs. > > --AA > > From develop4lasu at gmail.com Sun Mar 1 10:39:25 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Sun, 1 Mar 2009 19:39:25 +0100 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <49AABBA2.3040009@joda.org> References: <49AABBA2.3040009@joda.org> Message-ID: <28bca0ff0903011039n213e242dh52e2452e44ec856e@mail.gmail.com> Hello! I need add something MAJOR ADVANTAGE: It's multi-thread safe. Same goal for: final String aMember = g?.members?[0]?.name ?: "nobody"; would require for example: static String getBody(G g){ __ Member[] members = g==null ? null : g.members; __ Member member = members==null ? null : members[0]; __ String name = member==null ? "nobody" : member.name; __ return name; } final String aMember = g?.members?[0]?.name ?: "nobody"; >The ?: binary "Elvis" ... avoiding evaluation of the right-hand-side. I would like to see this operator more like: '?()' this would allow right-hand-side int len =g?.members?.[0]?.name ?("nobody") .length; I still wander how this operator should look like to be really easy to read '.?.' or '?.' or '?..'. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From reinier at zwitserloot.com Sun Mar 1 10:41:54 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Sun, 1 Mar 2009 19:41:54 +0100 Subject: PROPOSAL: Multiline strings In-Reply-To: <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> Message-ID: <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> Embedding regexps has two significant advantages: 1. compile-time checking of your regexps. Sure, most random gibberish just so happens to be a valid regexp, but there are rules - you can have mismatched parentheses, for example. 2. compile-time compilation of regexps. If compiling the regexp is allowed to take rather long, then you can effectively create O(n) matching algorithms, where n is the size of the input string. What better time is there to do the compilation of the regexp than when you're compiling the code? Javac would essentially include the serialized form of a compiled regexp into the class file, instead of the string. As far as the multi-line string proposal: It is very incomplete. I suggest resubmitting it with documentation on handling raw strings (let's leave regexp literals for another proposal; as has been said, even if the language has regexp literals, raw strings are still a useful constrict), and on handling white space. It should also cover handling of newlines (if the file contains \r\n because it was written on windows, should those be kept as is or should they be replaced with \n line-endings, which seems like the right answer to me). My personal favourite way to do whitespace: After the first newline, eliminate all leading whitespace. Then consider that amount of whitespace (no translating of tabs to spaces) to be the indent. Thus, the following: String foo = """ bar baz bla qux"; is equal to: String foo = "bar\n baz\n bla\nqux"; and the following: String foo = """ foo bar"""; is a compile-time error. If you need leading whitespace, you'll need to prefix this in a separate string and concatenate them, or add them on the same line. So, if you need "\t\nfoo\n", and you don't want to use \t, you could write it as: String foo = "" < - You don't see it, but there's a tab here. foo """; or as: String foo = "\t" + """ foo """; --Reinier Zwitserloot Like it? Tip it! http://tipit.to On Mar 1, 2009, at 18:53, Jeremy Manson wrote: > The plus side of the escaped String approach is that you can then use > any language, not just regexps. Also, escaped Strings might be a plus > for security purposes. > > Also, I'm not a big fan of the idea of embedding the > domain-specific-language-du-jour into my programming language. I see > it as a slippery slope. It's regexps today, but it's XML tomorrow > (I'm looking at you, Scala). > > Jeremy > > On Sun, Mar 1, 2009 at 1:16 AM, Adrian Kuhn wrote: >> On 01.03.2009, at 09:58, Jeremy Manson wrote: >> >>> Frankly, to me, the big win would actually not be multiline >>> literals, >>> but would be escaped String literals. I'm sick of writing all of my >>> regexps with twice as many \ characters as they need. >> >> In this case, why not allow regexps to be written literally in source >> code? As is done in many other languages. Although, this change would >> couple the regexp API with the language. But maybe here, the benefit >> might be worth the costs. >> >> --AA >> >> > From reinier at zwitserloot.com Sun Mar 1 10:49:06 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Sun, 1 Mar 2009 19:49:06 +0100 Subject: Proposal: Improved Wildcard Syntax for Java In-Reply-To: <15e8b9d20902282328v66a000e4ub1613d9811b86642@mail.gmail.com> References: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> <15e8b9d20902282328v66a000e4ub1613d9811b86642@mail.gmail.com> Message-ID: Neal, what I mean is the following sample cannot be translated to your 'out/in' syntax: public static > void sort(List list); The "T extends Comparable" part cannot be replaced with just 'out Comparable'. My suggestion involves allowing this to be rewritten as: public static > void sort(List list); Though, I share Stephen Colebourne's concern that the out/in syntax can be just as confusing in other situations, again highlighting how out/in and extends/super would co-exist (instead of a slow but steady migration towards out/in syntax), complicating the language. --Reinier Zwitserloot On Mar 1, 2009, at 08:28, Neal Gafter wrote: > On Sat, Feb 28, 2009 at 11:08 PM, Reinier Zwitserloot > wrote: >> This proposal is lacking in the 'disadvantages' section, in two ways. >> >> The listed disadvantage is unfairly sugared over; because the 'out/ >> in' >> terminology does not allow you to bind the generics parameter, the >> 'extends'/'super' syntax will never become outdated and the need to >> remember that 'out' is analogous to 'extends' and 'in' is analogous >> to >> 'super' does not go away. > > I don't understand. out/in bind the generic parameter in precisely > the same way that ?extends and ?super do. What you describe is a > disadvantage of the current syntax, but when using the new syntax you > don't have to remember it, because the new syntax is self-mneumonic. > >> There's another disadvantage that isn't listed at all: Neither 'in' >> nor 'out' are keywords in java currently. Therefore, you introduce >> the >> notion of a context-sensitive keyword, but as far as I understand it, >> java does not currently have context-sensitive keywords. Adding them >> is a big can of worms that should probably warrant some discussion >> (in >> the sense that it may complicate java parsers, and how the idea of >> context-sensitive keywords makes it a lot harder for any parser to >> use >> a keyword as an anchor point); at any rate it is a disadvantage that >> should be listed. > > Any change in syntax has to be considered for its interaction with > other tools, but for this particular case the general concerns you > express don't seem to be an issue. For example, this syntax is very > easy to parse with no more than the usual one-token lookahead. > >> There's also a typo in 'mneumonic' :) >> >> NB: For what it's worth, because the need to remember super-produces >> extends-consumes does not go away, I don't think this is going to >> help >> much. > > You don't have to remember that when reading and writing the new > syntax. > >> Perhaps make 'out' and 'in' valid context-sensitive keywords >> that can be used as a substitution for super and extends > > That's exactly what we've done, but with in/out you don't use the > question mark either. > >> and add that >> a missing generics variable on the LHS implies a wildcard? > > I don't understand what you propose, or see how it relates to this > proposal. From develop4lasu at gmail.com Sun Mar 1 11:10:20 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Sun, 1 Mar 2009 20:10:20 +0100 Subject: PROPOSAL: Multiline strings In-Reply-To: References: Message-ID: <28bca0ff0903011110k8bba3f8i4c14fb9de056c020@mail.gmail.com> Hello! MAJOR DISADVANTAGE: Code formatting can be some problem (visual). Now formatting consider code logic, not text logic. . Add to IDE (like eclipse,...) possibility to "paste escaped" "copy escaped" "view escaped" would not solve problem finally? And allow to keep language as it is? -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From akuhn at iam.unibe.ch Sun Mar 1 11:58:27 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 20:58:27 +0100 Subject: Use "default" keyword for default visibility. In-Reply-To: <1631da7d0903010907p2b3d0fd5nb03dca435608742e@mail.gmail.com> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> <6A1D1254-7506-4410-8DE2-795179B88F60@iam.unibe.ch> <1631da7d0903010907p2b3d0fd5nb03dca435608742e@mail.gmail.com> Message-ID: <99618040-66B2-40C1-BE5A-20006CBA5FBF@iam.unibe.ch> On Mar 1, 2009, at 18:07 , Jeremy Manson wrote: > I'm not sure that I understand how using a package qualifier would > actually help anyone's intuition in this case. It help by making it explicit. --AA From akuhn at iam.unibe.ch Sun Mar 1 12:03:07 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Sun, 1 Mar 2009 21:03:07 +0100 Subject: PROPOSAL: Multiline strings In-Reply-To: <28bca0ff0903011110k8bba3f8i4c14fb9de056c020@mail.gmail.com> References: <28bca0ff0903011110k8bba3f8i4c14fb9de056c020@mail.gmail.com> Message-ID: <4114D9EB-D2F5-442F-AA91-F0BA1806A078@iam.unibe.ch> On Mar 1, 2009, at 20:10 , Marek Kozie? wrote: > Add to IDE (like eclipse,...) possibility to "paste escaped" "copy > escaped" > "view escaped" would not solve problem finally? > And allow to keep language as it is? I would love to have "edit string" which pop-ups a text editor on the string's content. (Alas, I lack the Eclipse-Fu to hack this plugin myself.) --AA NB sorry, for being so offtopic. From jeremy.manson at gmail.com Sun Mar 1 13:17:49 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sun, 1 Mar 2009 13:17:49 -0800 Subject: Use "default" keyword for default visibility. In-Reply-To: <99618040-66B2-40C1-BE5A-20006CBA5FBF@iam.unibe.ch> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <1631da7d0903010115k8e9d868ld823066dc679ad4e@mail.gmail.com> <6A1D1254-7506-4410-8DE2-795179B88F60@iam.unibe.ch> <1631da7d0903010907p2b3d0fd5nb03dca435608742e@mail.gmail.com> <99618040-66B2-40C1-BE5A-20006CBA5FBF@iam.unibe.ch> Message-ID: <1631da7d0903011317r5f07e429ne186e62b44913e49@mail.gmail.com> I think I was perhaps unclear. I'm not sure how making it explicit would make people understand the inheritance properties (as described in your link) any better. If they don't know that package-private methods can't be overridden in those cases, then making it explicit seems unlikely to change that. Jeremy On Sun, Mar 1, 2009 at 11:58 AM, Adrian Kuhn wrote: > On Mar 1, 2009, at 18:07 , Jeremy Manson wrote: > >> I'm not sure that I understand how using a package qualifier would >> actually help anyone's intuition in this case. > > It help by making it explicit. > > --AA > From rssh at gradsoft.com.ua Sun Mar 1 10:15:00 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Sun, 1 Mar 2009 20:15:00 +0200 (EET) Subject: PROPOSAL: Multiline strings (EOL handling) In-Reply-To: <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> Message-ID: > Embedding regexps has two significant advantages: > ....... > I think that unescaped strings are useful not only for reqular expressions. Embedding of special syntax for regexprs -- may be this is another issue (and I afraid much less trivial then this) > > As far as the multi-line string proposal: It is very incomplete. I > suggest resubmitting it with documentation on handling raw strings > (let's leave regexp literals for another proposal; as has been said, > even if the language has regexp literals, raw strings are still a > useful constrict), and on handling white space. It should also cover > handling of newlines (if the file contains \r\n because it was written > on windows, should those be kept as is or should they be replaced with > \n line-endings, which seems like the right answer to me). > Sorry, but handling of newlines is described: After parsing multiline string is concatenation of lines with inseted value of system property 'line.separator' between thems. And 'line.separator' is '\n' on unix and '\r\n' on windows. but yes, replacing all end of lines to '\n' (string normalizing) make sence. (I will add issue) Yet on question: it can be optional or by default. I. e. variant OPTIONAL: a) we can add suffix "u" or "w" for unix-like or windows-like EOL handling and leave one as in program text by default. variant DEFAULT: b) always normalize multiline strings, by replacing '\r\n' to '\n' > My personal favourite way to do whitespace: > > After the first newline, eliminate all leading whitespace. Then .... (Ok, will add issue [next letter will be about this to spit different issues to different threads]) From rssh at gradsoft.com.ua Sun Mar 1 10:48:44 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Sun, 1 Mar 2009 20:48:44 +0200 (EET) Subject: PROPOSAL: Multiline strings (processing of whitespaces) In-Reply-To: <4114D9EB-D2F5-442F-AA91-F0BA1806A078@iam.unibe.ch> References: <28bca0ff0903011110k8bba3f8i4c14fb9de056c020@mail.gmail.com> <4114D9EB-D2F5-442F-AA91-F0BA1806A078@iam.unibe.ch> Message-ID: <2738e7cc1a4f2e6e46d6ae4fde76279e.squirrel@wmail.gradsoft.ua> About algorith of witespace processing, described by Reinier Zwitserloot: (see comments to http://redmine.gradsoft.ua/issues/show/161). Clearly we have next variants to choose from: A) keep multiline string without any special whitespace proccessing, but add special syntax (with four double quotes or suffixes) for whitespace processing. B) do whitespace processing by default, without any special form C) does not do any whitespace processing. is overkill or not ? look's fine (usially we have logic in identation). But let think twice about potential hidden problems ? Any ideas ? From mark at twistedbanana.demon.co.uk Sun Mar 1 17:57:26 2009 From: mark at twistedbanana.demon.co.uk (Mark Mahieu) Date: Mon, 2 Mar 2009 01:57:26 +0000 Subject: PROPOSAL: Multiline strings In-Reply-To: <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> Message-ID: <1FF9F7A4-C193-44A5-8C59-849922B2B391@twistedbanana.demon.co.uk> On 1 Mar 2009, at 06:50, rssh at gradsoft.com.ua wrote: > > 1. Since we have non-empty discussion, I setup wiki with current > proposal > ('new string literals instead multiline strings (?)') You may want to consider adding a couple of references to your proposal: http://bugs.sun.com/view_bug.do?bug_id=4472509 which has 76 votes, and links to a number of related bug reports http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd by Jacek Furmankiewicz, see the Kijaro mailing list archive for more information (https://kijaro.dev.java.net/) Regards, Mark From rssh at gradsoft.com.ua Sun Mar 1 18:38:11 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Mon, 2 Mar 2009 04:38:11 +0200 (EET) Subject: PROPOSAL: Multiline strings In-Reply-To: <1FF9F7A4-C193-44A5-8C59-849922B2B391@twistedbanana.demon.co.uk> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> <1FF9F7A4-C193-44A5-8C59-849922B2B391@twistedbanana.demon.co.uk> Message-ID: > > On 1 Mar 2009, at 06:50, rssh at gradsoft.com.ua wrote: > >> >> 1. Since we have non-empty discussion, I setup wiki with current >> proposal >> ('new string literals instead multiline strings (?)') > > > You may want to consider adding a couple of references to your proposal: > Added (interesting, that 4165111 have 0 votes, when 4472509 - 76) > http://bugs.sun.com/view_bug.do?bug_id=4472509 > which has 76 votes, and links to a number of related bug reports > > http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd > by Jacek Furmankiewicz, see the Kijaro mailing list archive for more > information (https://kijaro.dev.java.net/) > > > Regards, > > Mark > > From brucechapman at paradise.net.nz Mon Mar 2 00:23:57 2009 From: brucechapman at paradise.net.nz (Bruce Chapman) Date: Mon, 02 Mar 2009 21:23:57 +1300 Subject: Byte and short Integer Literals - discussion Message-ID: <49AB979D.9040301@paradise.net.nz> I am working on a proposal to add byte and short integer literals in order to ease some of the pain caused by byte being a signed type when most uses are just as a set of bits. Its mostly about byte size hexadecimal literals but other forms should be considered for completeness. One option ( work in progress at http://docs.google.com/Doc?docid=dcvp3mkv_0fvz5gx7b&hl=en ) is to allow integer type suffixes for byte (say y and Y) and short (say s and S) . That fits into the existing spec quite easily but looks a bit odd e.g. byte[] stuff = { 0x00y, 0x7Fy, 0x80y, 0xFFy }; Another approach would be to introduce a completely new syntax for hexadecimal integer literals which are typed according to the number of digits. for example (new syntax uses 0h compared with 0x for current int literals) byte b = 0hFF; short s = 0hFFFF; int i = 0hffffffff; long l = 0hffffffffffffffff; type determination would follow these rough rules. 1 or 2 digits -> byte literal 3 or 4 digits -> short 5 - 8 digits -> int 9 - 16 digits -> long. leading zeros permissible eg short s = 0h0000; So question: Do either of these stand out as superior (from a coin perspective) to the other in any significant way? I'd like to spend the majority effort on the better one if there is a significant preference on the mailing list. I am of two minds which is why I am asking. Bruce From rssh at gradsoft.com.ua Sun Mar 1 20:14:03 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Mon, 2 Mar 2009 06:14:03 +0200 (EET) Subject: Byte and short Integer Literals - discussion In-Reply-To: <49AB979D.9040301@paradise.net.nz> References: <49AB979D.9040301@paradise.net.nz> Message-ID: > integer type suffixes for byte (say y and Y) and short (say s and S) . > .... > Another approach would be to introduce a completely new syntax for > hexadecimal integer literals which are typed according to the number of ... I vote for suffixes. From rssh at gradsoft.com.ua Sun Mar 1 20:16:22 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Mon, 2 Mar 2009 06:16:22 +0200 (EET) Subject: Byte and short Integer Literals - discussion In-Reply-To: <49AB979D.9040301@paradise.net.nz> References: <49AB979D.9040301@paradise.net.nz> Message-ID: <7c991a71a0a7d27807517feac45aa7f3.squirrel@wmail.gradsoft.ua> > http://docs.google.com/Doc?docid=dcvp3mkv_0fvz5gx7b&hl=en ) is to allow > > byte[] stuff = { 0x00y, 0x7Fy, 0x80y, 0xFFy }; > Why 'y', not 'b' ? From reinier at zwitserloot.com Mon Mar 2 04:19:36 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 2 Mar 2009 13:19:36 +0100 Subject: Byte and short Integer Literals - discussion In-Reply-To: <7c991a71a0a7d27807517feac45aa7f3.squirrel@wmail.gradsoft.ua> References: <49AB979D.9040301@paradise.net.nz> <7c991a71a0a7d27807517feac45aa7f3.squirrel@wmail.gradsoft.ua> Message-ID: rssh: Because 'b' is a legal hexadecimal character. is 0xbb: '11 decimal as a byte literal', or is it '187 decimal as an int literal'? I think 0h as a general unsigned literal prefix that will automatically adjust its type based on length is far superior to introducing a gaggle of more or less random character suffixes - while doing byte hackery in java is painful, it still is a relatively small and niche aspect of java. In theory, every language aspect needs to be known implicitly by all java developers because its not easy to ask your IDE about showing you some javadoc for such a feature. Therefore, it should look obvious and simple, and not like voodoo, which 0x00y smacks of. Also, if you're going to go with suffixes, then for completeness sake, don't you need 6 suffixes total? (Byte Unsigned, Byte Signed, Short Unsigned, Short signed, int unsigned, long unsigned)? Just to highlight the mess that's going to become. Also note that the current suffix-L notation for long is part of a java puzzler (a minor one; l can be lowercase, which looks just like a 1, which is unfortunate). --Reinier Zwitserloot On Mar 2, 2009, at 05:16, rssh at gradsoft.com.ua wrote: >> http://docs.google.com/Doc?docid=dcvp3mkv_0fvz5gx7b&hl=en ) is to >> allow >> >> byte[] stuff = { 0x00y, 0x7Fy, 0x80y, 0xFFy }; >> > > Why 'y', not 'b' ? > > > > > From Joe.Darcy at Sun.COM Mon Mar 2 21:46:50 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 21:46:50 -0800 Subject: Proposal: Block Expressions for Java In-Reply-To: <15e8b9d20902272130i3e52b349ta500f4b98accec01@mail.gmail.com> References: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> <15e8b9d20902272130i3e52b349ta500f4b98accec01@mail.gmail.com> Message-ID: <49ACC44A.1040609@sun.com> Hi Neal. While I have some sympathy for expression-oriented rather than statement-oriented languages, my general reaction to this proposal is that it doesn't offer much incremental utility for expressing and simplifying programming idioms commonly used today, which is the main goal for Project Coin. Some more comments in line... Neal Gafter wrote: > [Resending in plain text] > > Block Expressions for Java > > AUTHOR(S): > > Neal Gafter > > OVERVIEW > > FEATURE SUMMARY: > > A parenthesized expression can now contain additional statements, for > example declarations of temporary local variables to avoid recomputing > a value used only within the expression. This feature is especially > useful in machine-generated code. > > MAJOR ADVANTAGE: > > Allows the declaration of local temporary variables closer to the > point of use. Simplifies programs that generate Java code, as > temporary variables that are used in only a single expression can be > declared with the expression. > > MAJOR BENEFIT: > > Simplifies some patterns of code (see above). Makes it easier to > write expression-oriented code even though many APIs are statement- or > side-effect-oriented. Allows temporaries to be declared closer to the > point of use. > > MAJOR DISADVANTAGE: > > Slightly more complex language specification. Like most other > language features, can be overused to the detriment of the readability > of the code. > > ALTERNATIVES: > > In many cases, there are alternate though awkward ways of writing the > code, such as introducing small helper functions that are used only > once or introducing temporary variables. > > EXAMPLES > > SIMPLE EXAMPLE: > > double pi2 = (double pi = Math.PI ; pi*pi); // pi squared > > ADVANCED EXAMPLE: > > public static final Map primes = ( > Map t = new HashMap(); > t.put(1, 2); t.put(2, 3); t.put(3, 5); t.put(4, 7); > Collections.UnmodifiableMap(t)); > > DETAILS > > SPECIFICATION: > > Grammar: the grammar for a parenthesized expression [JLS 15.8.5] is changed to: > > ParExpression: > ( BlockStatementsopt Expression ) > > Note that the existing syntax for a parenthesized expression is a > special case of this. > > Meaning of Expressions: The specification for a parenthesized > expression should be modified to describe its new execution semantics: > The block statements (if any) are executed in sequence, from left to > right, exactly as in a block statement. The result of the > parenthesized expression is the result of evaluating its > subexpression. > So what about return, break, and continue statements inside the BlockStatements? > Definite Assignment: The definite assignment rules for this construct > are almost identical to that for the block statement. The definite > assignment state before the subexpression is the definite assignment > state following the last block statement. > > Exception Checking: A parenthesized expression can throw exception > type E if any statement or expression immediately contained in it can > throw E. > > Scoping: Local variables and classes declared by an immediately > contained statement is in scope until the end of the parenthesized > expression. > > Meaning of Statements: No changes. > > Type System: No changes. > > COMPILATION: > > Compilation is straightforward, with one minor exception (no pun > intended). The compiler must arrange the generated code such that the > stack is empty at the beginning of any try statement that can complete > normally when the try statement is embedded within a parenthesized > expression. That is because the VM empties the stack when exceptions > are handled. This can be accommodated by spilling values from the > stack into VM locals. > That doesn't necessarily sound minor! > TESTING: > > Since the language change is completely local, it can be tested by > exercising each of its interactions described above. > > LIBRARY SUPPORT: > > None required. > > REFLECTIVE APIS: > > No changes required. > > OTHER CHANGES: > > It would be desirable, at the same time that this change is made, to > update the non-public Tree API that can be used with APT to express > the syntax extension. > FYI and to be precise on notation, we will *not* be updating apt to work with JDK 7 language features at all. In contrast, the JSR 269 language model and annotation processing API used by javac will be updated. The tree API will be updated as needed for any new language features, and, as you imply, using javac-specific APIs (i.e. non JCP APIs) it is possible to use the Tree API with JSR 269 annotation processing. Cheers, -Joe > MIGRATION: > > None required. > > COMPATIBILITY > > BREAKING CHANGES: > > No breaking changes. > > EXISTING PROGRAMS: > > No effect on existing programs. This is a pure extension. > > REFERENCES > > EXISTING BUGS: > > None. > > URL FOR PROTOTYPE (optional): > > None. > > From philvarner at gmail.com Mon Mar 2 22:11:50 2009 From: philvarner at gmail.com (Phil Varner) Date: Mon, 2 Mar 2009 22:11:50 -0800 Subject: Proposal: Import Aliases for Classes and Static Methods Message-ID: Import Aliases for Classes and Static Methods http://docs.google.com/Doc?id=dgx74dt7_19dxnspbhj AUTHOR: Phil Varner OVERVIEW FEATURE SUMMARY: The import aliases feature allows a user to provide an alias underwhich an imported class or statically imported method must be referred to in the containing source file. An example of the use of this feature is "import java.sql.Date as SqlDate;" MAJOR ADVANTAGE: This feature would allow easier use of multiple classes which have the same name but different packages to be used in the same source file. MAJOR BENEFIT: This will prevent the necessity of fully-qualifiying all class references when there is a name collision, leading to more readable code. MAJOR DISADVANTAGE: This will introduce an extra level of indirection when determing the source of a given class or method, introduce a new keyword 'as', and will require changes to IDE code completion functionality. ALTERNATIVES: In some cases, a nested class can be created which trivially derives a class involved in the name collision. For a method, a wrapper method can be created in the source file. EXAMPLES SIMPLE EXAMPLE: Example #1, duplicate class name Current code: new java.sql.Date(new java.util.Date()); New code: import java.sql.Date as SqlDate; import java.util.Date as UtilDate; new SqlDate(new UtilDate()); Example #2, statically imported method alias Current code: import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName; public static int mrlacsmn(final int arg1, final String arg2){ return myReallyLongAndComplicatedStaticMethodName(arg1, arg2); } mrlacsmn(1, a); New code: import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName as mrlacsmn; mrlacsmn(1, a); ADVANCED EXAMPLE: Example #3 Translation of persistent formats between similar APIs. In many domains, it is not uncommon to have two different APIs with classes with the same name. For example, in a production rules API, one may have classes "RuleSet" and "Rule". When attempting to use the API to translate between these these APIs, it must be decided that one is fully-qualified and one is not. This can lead to code like: com.example.foo.bar.sdk.RuleSet srcRuleSet = ...; com.example.foo.bar.sdk2.RuleSet dstRuleSet = new com.example.foo.bar.sdk2.RuleSet(); migrate(srcRuleSet, dstRuleSet); ... private static void migrate(com.example.foo.bar.sdk.RuleSet srcRuleSet, com.example.foo.bar.sdk2.RuleSet dstRuleSet){ ... } Note that it is good practice here not to import either class because it is too easy to accidentally misuse constants and static methods. With the 'as' syntax, one could instead write the far less verbose and more readible: import com.example.foo.bar.sdk.RuleSet as SrcRuleSet; import com.example.foo.bar.sdk2.RuleSet as DstRuleSet; ... SrcRuleSet srcRuleSet = ...; DstRuleSet destRuleSet = new DstRuleSet(); migrate(srcRuleSet, dstRuleSet); ... private static void migrate(SrcRuleSet srcRuleSet, DstRuleSet dstRuleSet){ ... } Example #4 Ensuring correct method selection when static importing overloaded methods. Current code: import static org.testng.Assert.assertEquals; public static int aeo(Object arg1, Object arg2){ assertEquals(arg1, arg2); } public static int aec(Collection arg1, Collection arg2){ assertEquals(arg1, arg2); } aeo(obj1, obj2); aec(list1, list2); New code: import static org.testng.Assert.assertEquals(Object, Object) as aeo; import static org.testng.Assert.assertEquals(Collection, Collection) as aec; aeo(obj1, obj2); aec(list1, list2); Note: it is possible that this sort of method selection is beyond the scope of a COIN proposal DETAILS SPECIFICATION: Grammar modification (JLS 3.9): Keyword: as ... modification (JLS 7.5): ImportDeclaration: SingleTypeImportDeclarationWithAlias SingleStaticImportDeclarationWithAlias ... addition: SingleTypeImportDeclarationWithAlias: import TypeName as Identifier; addition: SingleStaticImportDeclarationWithAlias: import static TypeName . Identifier as Identifier; Note that this would explicitly forbid wildcard imports from being aliased. There are no known effects on the type system or meaning of expressions and statements in the Java Programming Language. COMPILATION: This feature would be a compile-time transform. It would only affect the way in which a non-fully qualified class or method name was resolved to a fully-qualified class or method name. TESTING: This change would be tested in a manner similar how how the existing code which resolves the fully-qualified names of classes and methods is tested. LIBRARY SUPPORT: No change REFLECTIVE APIS: No change OTHER CHANGES: No change MIGRATION: This change is backwards-compatible with existing code. COMPATIBILITY BREAKING CHANGES: No change EXISTING PROGRAMS: No change REFERENCES EXISTING BUGS: None at present URL FOR PROTOTYPE (optional): None at present From Joe.Darcy at Sun.COM Mon Mar 2 22:29:29 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 22:29:29 -0800 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> Message-ID: <49ACCE49.8030103@sun.com> Hello. Comments in line... Neal Gafter wrote: > [Resending in plain text] > > Improved Exception Handling for Java > > AUTHOR(S): > > Neal M Gafter > > OVERVIEW > > FEATURE SUMMARY: > > Catching multiple exception types: A single catch clause can now catch > more than one exception types, enabling a series of otherwise > identical catch clauses to be written as a single catch clause. > Improved checking for rethrown exceptions: Previously, rethrowing an > exception was treated as throwing the type of the catch parameter. > Now, when a catch parameter is declared final, rethrowing the > exception is known statically to throw only those checked exception > types that were thrown in the try block, are a subtype of the catch > parameter type, and not caught in preceding catch clauses. > > MAJOR ADVANTAGE: > > Catching multiple exception types: Simplifies a commonly appearing > pattern of redundant code. > Improved checking for rethrown exceptions: This improvement makes it > possible to add a try-catch statement around a block of code to > intercept, process, and rethrow an exception without affecting the > statically determined set of exceptions thrown from the code. > > MAJOR BENEFIT: > > Greatly simplifies writing and maintaining code where intercepting or > processing exceptions is common. > > MAJOR DISADVANTAGE: > > One-time implementation cost for adding the features to the compiler. > Longer language specification in describing the behavior. > What sort of poor programming practices could this feature encourage or enable? > ALTERNATIVES: > > These behaviors are approximated currently by writing a series of > identical catch clauses. During maintenance, the set of catch clauses > must be modified so that it continues to match the set of exceptions > statically thrown in the try block. With the proposed changes, the > catch block can be written to catch a supertype of the set of > exceptions to be intercepted, resulting in fewer catch clauses and > fewer changes required when the try block evolves. > Another poor alternative used too often in practice is to catch a too general type, like Throwable, to avoid repeating more specific catch clauses. > EXAMPLES > > SIMPLE EXAMPLE: > > try { > doWork(file); > } catch (final IOException|SQLException ex) { > logger.log(ex); > throw ex; > } > > ADVANCED EXAMPLE: > > Show advanced usage(s) of the feature. > > DETAILS > > SPECIFICATION: > > The grammar of Java is extended to allow a series of exception types, > separated by the "OR" operator symbol, to be used in a catch clause: > > CatchClause: > catch ( CatchFormalParameter ) Block > CatchFormalParameter: > VariableModifiers CatchType VariableDeclaratorId > CatchType: > DisjunctionType > DisjunctionType: > Type > Type | DisjunctionType > > The type system is affected as follows: For the purpose of type > checking, a catch parameter declared with a disjunction has type > lub(t1, t2, ...) [JLS3 15.12.2.5]. In terms of finding the members of the type, it is good existing concepts in the JLS can be used. What happens if someone writes catch(final IOException | SomeSubclassOfIOException e) {...} In other words, is it legal to have subclasses of a caught exception listed too? > For the purpose of exception > checking [JLS3 11.2], a throw statement [JLS3 11.2.2] that rethrows a > final catch parameter is treated as throwing precisely those exception > types that > > the try block can throw, > no previous catch clause handles, and > is a subtye of one of the types in the declaration of the catch parameter > > To avoid the need to add support for general disjunctive types, but > leaving open the possibility of a future extension along these lines, > a catch parameter whose type has more than one disjunct is required to > be declared final. > I think that is a fine compromise that keep the current feature smaller while allowing room for a broader feature later. Some worked examples of the sets of thrown exceptions types under various tricky code samples would help clarify the data flow algorithm for me. > COMPILATION: > > A catch clause is currently compiled (before this change) to an entry > in an exception table that specifies the type of the exception and the > address of the code for the catch body. To generate code for this new > construct, the compiler would generate an entry in the exception table > for each type in the exception parameter's list of types. > Interesting; so there would be no code duplication even in the class files. > TESTING: > > The feature can be tested by compiling and running programs that > exercise the feature. > > LIBRARY SUPPORT: > > No. > > REFLECTIVE APIS: > > No reflective API changes are required. > > OTHER CHANGES: > > It would be desirable, at the same time that this change is made, to > update the non-public Tree API that can be used with APT to express > the syntax extension. > The Tree API (http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) has a bit different situation than other APIs in the JDK. The tree API is *not* a JCP API, but we at Sun choose to ship it and document it as part of Sun's JDK. So the API is public in that sense, but it has a different support, stability, and compatibility contract than JCP APIs. > MIGRATION: > > None required. However, it would be easy to detect a series of > otherwise identical catch clauses for different types and collapse > them to a single catch clause. > > COMPATIBILITY > > BREAKING CHANGES: > > Joe Darcy observes that the following program compiles before this > change, but not after: > > try { > throw new DaughterOfFoo(); > } catch (final Foo exception) { > try { > throw exception; // used to throw Foo, now throws DaughterOfFoo > } catch (SonOfFoo anotherException) { // Reachable? > } > } > > However > > This breakage is compile-time-only; already-compiled programs continue > to behave as before > This kind of breakage is very unlikely to occur in practice, and > The broken code was likely wrong before, as it attempts to catch > exceptions that simply cannot occur. > I am a bit concerned by the existence of such a program, as uncommon or ill-posed as it might be. It is preferable to have a pure extension that doesn't invalidate any existing programs. The platform promises JLS chapter 13 binary compatibility from release to release; that binary compatibility is defined to be the continued ability to link, nothing more. Source compatibility is *not* promised from release to release, and source compatibility is not defined in the JLS (I take a stab at drawing out source compatibility thread levels in http://blogs.sun.com/darcy/entry/kinds_of_compatibility). However, source compatibility should be maintained if possible. How could the increased exception precision be maintained will still allow programs such as the one above to compile? Thanks for sending this in, -Joe > EXISTING PROGRAMS: > > Except as above, none. > > REFERENCES > > EXISTING BUGS: > > No existing bugs that I am aware of. > > URL FOR PROTOTYPE (optional): > > An implementation of disjunctive catch parameters, but without special > handling for final catch parameters: > > http://www.javac.info/ > > See also > > Catching Multiple Exception Types: http://www.javac.info/Multicatch.html > Improved Checking for Rethrown Exceptions: http://www.javac.info/Rethrown.html > > From rhvarona at gmail.com Mon Mar 2 21:02:08 2009 From: rhvarona at gmail.com (Roger Hernandez) Date: Tue, 3 Mar 2009 00:02:08 -0500 Subject: Simple Resource Clean-up Message-ID: I saw how the previous Automatic Resource Management proposal got torn to pieces but I feel strongly enough about this issue to post a similar proposal. Some points: I am not a programming language designer. I have very little experience with byte code and with design and implementation of compilers. What I do have is many years of experience in writing code for large business applications, both in house-custom programs and shrink-wrapped products sold to customers. About 1/3 of the Java code I write contributes almost nothing to the functionality or flexibility of the program. It is composed of very simple and very repetitive resource clean-up code. JDBC code is an especially bad case. I know we should be using JDO or JPA, but: 1) most of the Java database code in existence is using JDBC to some extent or another, 2) for the kind of processing our software does with large datasets having hundreds of megabytes of row data and millions of rows per account per month, custom JDBC code still beats the other solutions in memory utilization and throughput. In most business code we don't do complex exception processing. If we get a exception we rollback the transaction and unroll the stack until we reach some program level error handler that logs the error for some administrator to review at a later date. So if this proposal is not applicable to complex error handling scenarios, that is fine. Taking care of the simple scenarios will still get rid of most of that 1/3 of the code I write, allowing me to concentrate on the actual program logic, not the resource clean-up noise. I also program quite a bit in C++ and C# and when I work in Java I sorely miss RAII (Resource Acquisition Is Initialization) and the "using" statement respectively. At the end of the day, what I would like is a solution to minimize all the resource clean-up boiler plate. ----------------------------------------------------------------------------------------- PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR: Roger Hernandez, rogerh at velocityconsultinginc.com OVERVIEW FEATURE SUMMARY: Syntactic sugar for simple cases of the common new/try/finally/close language idiom. The object being created must implement the Closeable interface. MAJOR ADVANTAGE: Significantly reduces lines of code when working with objects that encapsulate external resources that should be closed as soon as possible. Examples are Stream, Reader, Writer classes in java.io, and Connection, Statement, PreparedStatement, ResultSet in java.sql.*. MAJOR BENEFIT: It allows writing code that uses these kinds of object to more clearly express the both the lifetime of the utilization of each resource, and allows the logic flow of the code to be more visible. MAJOR DISADVANTAGE: Either a new keyword, or an additional overloaded meaning on an existing keyword. ALTERNATIVES: You can always use the standard idiom: SomeType val = new val(...); try { ... } finally { val.close(); } EXAMPLES SIMPLE EXAMPLE: A simple Java version of the command line utility "tee". //This is the existing way of doing it. //Lines of code: 19 package com.vci.projectcoin.using; import java.io.*; public class SimpleExample { public static void main(String[] args) throws IOException { byte []buffer = new byte[1024]; FileOutputStream out = new FileOutputStream(args[0]); try { for (int count; (count = System.in.read(buffer)) != -1;) { out.write(buffer, 0, count); System.out.write(buffer, 0, count); } } finally { out.close(); } } } //This is the proposed way of doing it, the compiler converts the syntactic sugar into the same byte codes //I am adding a new use to the the "try" keyword to avoid adding more to the language, but it would work //just a well with a "using" keyword. //Lines of code: 16 package com.vci.projectcoin.using; import java.io.*; public class SimpleExample { public static void main(String[] args) throws IOException { byte []buffer = new byte[1024]; try (FileOutputStream out = new FileOutputStream(args[0])) { for (int count; (count = System.in.read(buffer)) != -1;) { out.write(buffer, 0, count); System.out.write(buffer, 0, count); } } } } ADVANCED EXAMPLE: A simple utility to execute a query and write values as a comma delimited file. //This is the existing way of doing it //Lines of code: 55 package com.vci.projectcoin.using; import java.sql.*; import java.io.*; public class AdvancedExample { final static String EOL = System.getProperty("line.separator"); //Command Line: [] static public void main(String []args) throws SQLException, FileNotFoundException { String url = args[0]; String sql = args[1]; PrintWriter out = new PrintWriter(args.length > 2 ? new FileOutputStream(args[2]) : System.out); try { Connection conn = DriverManager.getConnection(url); try { Statement query = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); try { ResultSet results = query.executeQuery(sql); try { ResultSetMetaData meta = results.getMetaData(); int colCount = meta.getColumnCount(); while (results.next()) { for (int index = 1; index <= colCount; index++) { int colType = meta.getColumnType(index); boolean quoted = colType == Types.CHAR || colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; if (quoted) { System.out.append('"'); } System.out.append(results.getString(index)); if (quoted) { System.out.append('"'); } if (index < colCount) { System.out.print(','); } else { System.out.print(EOL); } } } } finally { results.close(); } } finally { query.close(); } } finally { conn.close(); } } finally { out.close(); } } } //This is the proposed way of doing it //This proposal gets rid of the finally clean up per object. It lets one write robust resource clean-up code without a lot of effort. //Lines of code: 43 package com.vci.projectcoin.using; import java.sql.*; import java.io.*; public class AdvancedExample { final static String EOL = System.getProperty("line.separator"); //Command Line: [] static public void main(String []args) throws SQLException, FileNotFoundException { String url = args[0]; String sql = args[1]; try (PrintWriter out = new PrintWriter(args.length > 2 ? new FileOutputStream(args[2]) : System.out)) { try (Connection conn = DriverManager.getConnection(url)) { try (Statement query = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) { try (ResultSet results = query.executeQuery(sql)) { ResultSetMetaData meta = results.getMetaData(); int colCount = meta.getColumnCount(); while (results.next()) { for (int index = 1; index <= colCount; index++) { int colType = meta.getColumnType(index); boolean quoted = colType == Types.CHAR || colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; if (quoted) { System.out.append('"'); } System.out.append(results.getString(index)); if (quoted) { System.out.append('"'); } if (index < colCount) { System.out.print(','); } else { System.out.print(EOL); } } System.out.println(); } } } } } } } //This is an additional syntactic sugar proposal, allowing multiple objects to be allocated inside one try block. The compiler converts all three programs into the same bytecode //This proposal gets rid of the additional indentation level and closing brace per object. It further minimize the clean-up boiler-plate, allowing the point of the program logic to be clearer. //Lines of code: 38 package com.vci.projectcoin.using; import java.sql.*; import java.io.*; public class AdvancedExample { final static String EOL = System.getProperty("line.separator"); //Command Line: [] static public void main(String []args) throws SQLException, FileNotFoundException { String url = args[0]; String sql = args[1]; try (PrintWriter out = new PrintWriter(args.length > 2 ? new FileOutputStream(args[2]) : System.out), Statement query = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY), ResultSet results = query.executeQuery(sql)) { ResultSetMetaData meta = results.getMetaData(); int colCount = meta.getColumnCount(); while (results.next()) { for (int index = 1; index <= colCount; index++) { int colType = meta.getColumnType(index); boolean quoted = colType == Types.CHAR || colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; if (quoted) { System.out.append('"'); } System.out.append(results.getString(index)); if (quoted) { System.out.append('"'); } if (index < colCount) { System.out.print(','); } else { System.out.print(EOL); } } System.out.println(); } } } } DETAILS The specification requires that the object in the try () block have a "close()" method. Wether the method throws any or no exception, or if it returns a value or no value does not matter. The proposal is not trying to introduce any new intelligence into the try finally clause, it is just syntactic sugar to minimize simple resource clean-up code. SPECIFICATION: The "try" keyword will have an overloaded meaning CASE 1 ------ try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { //work gets done here } Will be syntactic sugar for: ClassWithCloseMethod value = new ClassWithCloseMethod(...); try { //work gets done here } finally { value.close(); } CASE 2 ------ try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { //work gets done here } finally { //additional clean-up code } Will be syntactic sugar for: ClassWithCloseMethod value = new ClassWithCloseMethod(...); try { //work gets done here } finally { value.close(); //additional clean-up code } CASE 3 ------ try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { //work gets done here } catch (Exception ex) { //exception handling code } finally { //additional clean-up code } Will be syntactic sugar for: ClassWithCloseMethod value = new ClassWithCloseMethod(...); try { //work gets done here } catch (Exception ex) { //exception handling code } finally { value.close(); //additional clean-up code } CASE 4 ------ try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { //work gets done here } Will be syntactic sugar for: Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); try { Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); try { Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); try { //work gets done here } finally { value3.close(); } } finally { value2.close(); } } finally { value1.close(); } CASE 5 ------ try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { //work gets done here } finally { //additional clean-up code } Will be syntactic sugar for: Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); try { Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); try { Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); try { //work gets done here } finally { value3.close(); } } finally { value2.close(); } } finally { value1.close(); //additional clean-up code } CASE 6 ------ try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { //work gets done here } catch (Exception ex) { //exception handling code } finally { //additional clean-up code } Will be syntactic sugar for: Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); try { Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); try { Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); try { //work gets done here } finally { value3.close(); } } finally { value2.close(); } } catch (Exception ex) { //exception handling code } finally { value1.close(); //additional clean-up code } COMPILATION: The SPECIFICATION section above shows the desugaring for each case. Byte code would be identical to the desugared constructs. TESTING: Byte code comparison of common code constructs. If the byte code is not identical to the desugared version, test fails. LIBRARY SUPPORT: No. REFLECTIVE APIS: No. OTHER CHANGES: No. MIGRATION: For each case in the SPECIFICATION section, convert the existing code to the syntactic sugar proposal. COMPATIBILITY BREAKING CHANGES: None. EXISTING PROGRAMS: Compile accepts both existing and new forms of the "try" statement. Byte code does not change. REFERENCES EXISTING BUGS: None -- Roger Hernandez From Joe.Darcy at Sun.COM Mon Mar 2 22:34:24 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 22:34:24 -0800 Subject: PROPOSAL: Multiline strings In-Reply-To: <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> Message-ID: <49ACCF70.20908@sun.com> rssh at gradsoft.com.ua wrote: > 1. Since we have non-empty discussion, I setup wiki with current proposal > ('new string literals instead multiline strings (?)') > > http://redmine.gradsoft.ua/wiki/java7stringliterals > and will try to track all changes as issues. > The Project Coin mailing list is the place for discussion of proposals submitted to Project Coin! -Joe From Joe.Darcy at Sun.COM Mon Mar 2 22:35:41 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 22:35:41 -0800 Subject: PROPOSAL: Multiline strings In-Reply-To: <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> Message-ID: <49ACCFBD.3010509@sun.com> Reinier Zwitserloot wrote: > Embedding regexps has two significant advantages: > > 1. compile-time checking of your regexps. Sure, most random > gibberish just so happens to be a valid regexp, but there are rules - > you can have mismatched parentheses, for example. > At least in principle tools can do this kind of checking without language support. -Joe From Joe.Darcy at Sun.COM Mon Mar 2 22:44:11 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 22:44:11 -0800 Subject: PROPOSAL: Multiline strings In-Reply-To: References: Message-ID: <49ACD1BB.7060505@sun.com> Ruslan, This proposal is missing many important details. rssh at gradsoft.com.ua wrote: > AUTHOR(s): Ruslan Shevchenko > > OVERVIEW: > FEATURE SUMMARY: > add multiline strings to java language. > MAJOR ADVANTAGE: > Possibility more elegant to write code part of codes in other languages, > such as sql constructions or rendering of html components. > MAJOR DISADVANTAGE > I don't know > ALTERNATIVES: > use String "+=" operator. > using groovy instead java in utility classes. > "This is \n" + "an alternative \n" + "too.\n" As is concat("If you save on \"\\n\", "you might still pay ", "with a comma."); public static concat(String... args) { // concat args together separated by newlines } > EXAMPLES > > SIMPLE EXAMPLE: > > StringBuilder sb = new StringBuilder(); > sb.append("""select a from Area a, CountryCodes cc > where > cc.isoCode='UA' > and > a.owner = cc.country > """); > if (question.getAreaName()!=null) { > sb.append("""and > a.name like ? > """); > sqlParams.setString(++i,question.getAreaName()); > } > > instead: > StringBuilder sb = new StringBuilder(); > sb.append("select a from Area a, CountryCodes cc\n"); > sb.append("where cc.isoCode='UA'\n"); > sb.append("and a.owner=cc.country'\n"); > if (question.getAreaName()!=null) { > sb.append("and a.name like ?"); > sqlParams.setString(++i,question.getAreaName()); > } > > > DETAILS: > Multiline strings are part of program text, which begin and ends > by three double quotes. (as in groovy and scala) Text withing such > brackets processed as multiline string with all rulles as normal Java > string literals, except it can be multiline. After parsing multiline > string is concatenation of lines with inserted value of system property > 'line.separator' between thems. > What are the grammar changes? Is are three consecutive quote characters escaped in a multi-line string? As has been mentioned in earlier responses, how is whitespace handed? > COMPILATION: > Multiline strings created and used in .class files exactly as ordinary > strings. > What is the desugaring? Regards, -Joe > TESTING: > Nothing special. add multiline strings to test-cases. > > LIBRARY SUPPORT: > None. > (May be exists sence add simple template processing to standard library, but > I think this is goal of next janguage iteration. Now exists many good > external > frameworks, such as velocity: better wait and standartize support of > winner) > > REFLECTIVE APIS: None > > OTHER CHANGES: None > > MIGRATION: None > > COMPABILITY > None > > REFERENCES > > http://bugs.sun.com/view_bug.do?bug_id=4165111 > > > > > > > > From Joe.Darcy at Sun.COM Mon Mar 2 23:04:44 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Mon, 02 Mar 2009 23:04:44 -0800 Subject: Notes on implementing concise calls to constructors with type parameters Message-ID: <49ACD68C.2010405@sun.com> Hello. As implied by previous email on the list, Neal and I met recently and discussed an implementation strategy for supporting concise calls to constructors with type parameters using the diamond "<>" notation. In brief, since the desired behavior to emulate is having the bounds of constructors determined as if a static generic factory method was used instead, the compiler could synthesize artificial static methods for the purposes of method resolution and finding the bounds, but then discard those synthesized methods and map back to the right constructor. There are a few hazards to watch out for: * Generic constructors that declare their own type variables * accessibility modifiers * var-args * boxing/unboxing conversion The running example was something like class C { C(Arg1 arg1) C(Arg 1 arg1, Arg 2 arg2) C(Arg 1 arg1) } Both T and U could appear in the argument list somewhere; they could also have bounds. The translation would be to static /* orig. modifiers */ C staticFactory(/* orig. list of args*/) where S is just an alpha-rename of T and U would be omitted for non-generic constructors. Once the appropriate constructor with its bound is chosen, inference might have to be redone on the constructor to bind any generic type parameters (and account for var-args and boxing and unboxing). Any diagnostic messages should be mapped back to the constructors rather than the synthesized static factories. The resolution process results in Symbols and only the phases through Attr and Resolved should need to be modified. This mapping of static factories to constructors should probably inform the specification of the feature as well as its implementation, but I haven't written any specification along those lines. Regards, -Joe From neal at gafter.com Mon Mar 2 23:23:41 2009 From: neal at gafter.com (Neal Gafter) Date: Mon, 2 Mar 2009 23:23:41 -0800 Subject: Simple Resource Clean-up In-Reply-To: References: Message-ID: <15e8b9d20903022323k17c3f1afo9919c311070b17be@mail.gmail.com> You say "The object being created must implement the Closeable interface." But java.sql.Statement, to pick one example, cannot be made to implement that interface because the exception signatures are not compatible. I'll let others comment about issues with exception handling in the translation. -Neal On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez wrote: > I saw how the previous Automatic Resource Management proposal got torn to > pieces but I feel strongly enough about this issue to post a similar > proposal. > > Some points: > > I am not a programming language designer. ?I have very little experience > with byte code and with design and implementation of compilers. ?What I do > have is many years of experience in writing code for large business > applications, both in house-custom programs and shrink-wrapped products sold > to customers. > > About 1/3 of the Java code I write contributes almost nothing to the > functionality or flexibility of the program. ?It is composed of very simple > and very repetitive resource clean-up code. ?JDBC code is an especially bad > case. ?I know we should be using JDO or JPA, but: 1) most of the Java > database code in existence is using JDBC to some extent or another, 2) for > the kind of processing our software does with large datasets having hundreds > of megabytes of row data and millions of rows per account per month, custom > JDBC code still beats the other solutions in memory utilization and > throughput. > > In most business code we don't do complex exception processing. ?If we get a > exception we rollback the transaction and unroll the stack until we reach > some program level error handler that logs the error for some administrator > to review at a later date. ?So if this proposal is not applicable to complex > error handling scenarios, that is fine. ?Taking care of the simple scenarios > will still get rid of most of that 1/3 of the code I write, allowing me to > concentrate on the actual program logic, not the resource clean-up noise. > > I also program quite a bit in C++ and C# and when I work in Java I sorely > miss RAII (Resource Acquisition Is Initialization) and the "using" statement > respectively. > > At the end of the day, what I would like is a solution to minimize all the > resource clean-up boiler plate. > > ----------------------------------------------------------------------------------------- > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > > ? AUTHOR: Roger Hernandez, rogerh at velocityconsultinginc.com > > OVERVIEW > > ? FEATURE SUMMARY: Syntactic sugar for simple cases of the common > new/try/finally/close language idiom. ?The object being created must > implement the Closeable interface. > > ? MAJOR ADVANTAGE: Significantly reduces lines of code when working with > objects that encapsulate external resources that should be closed as soon as > possible. ?Examples are Stream, Reader, Writer classes in java.io, and > Connection, Statement, PreparedStatement, ResultSet in java.sql.*. > > ? MAJOR BENEFIT: It allows writing code that uses these kinds of object to > more clearly express the both the lifetime of the utilization of each > resource, and allows the logic flow of the code to be more visible. > > ? MAJOR DISADVANTAGE: Either a new keyword, or an additional overloaded > meaning on an existing keyword. > > ? ALTERNATIVES: You can always use the standard idiom: SomeType val = new > val(...); try { ... } finally { val.close(); } > > EXAMPLES > > ? SIMPLE EXAMPLE: ?A simple Java version of the command line utility "tee". > ? ? ?//This is the existing way of doing it. > ? ? ?//Lines of code: 19 > ? ? ?package com.vci.projectcoin.using; > > ? ? ?import java.io.*; > > ? ? ?public class SimpleExample { > > ? ? ? ? public static void main(String[] args) throws IOException { > ? ? ? ? ? ?byte []buffer = new byte[1024]; > ? ? ? ? ? ?FileOutputStream out = new FileOutputStream(args[0]); > ? ? ? ? ? ?try { > ? ? ? ? ? ? ? for (int count; (count = System.in.read(buffer)) != -1;) { > ? ? ? ? ? ? ? ? ?out.write(buffer, 0, count); > ? ? ? ? ? ? ? ? ?System.out.write(buffer, 0, count); > ? ? ? ? ? ? ? } > ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? out.close(); > ? ? ? ? ? ?} > ? ? ? ? } > ? ? ?} > > ? ? ?//This is the proposed way of doing it, the compiler converts the > syntactic sugar into the same byte codes > ? ? ?//I am adding a new use to the the "try" keyword to avoid adding more > to the language, but it would work > ? ? ?//just a well with a "using" keyword. > ? ? ?//Lines of code: 16 > ? ? ?package com.vci.projectcoin.using; > > ? ? ?import java.io.*; > > ? ? ?public class SimpleExample { > > ? ? ? ? public static void main(String[] args) throws IOException { > ? ? ? ? ? ?byte []buffer = new byte[1024]; > ? ? ? ? ? ?try (FileOutputStream out = new FileOutputStream(args[0])) { > ? ? ? ? ? ? ? for (int count; (count = System.in.read(buffer)) != -1;) { > ? ? ? ? ? ? ? ? ?out.write(buffer, 0, count); > ? ? ? ? ? ? ? ? ?System.out.write(buffer, 0, count); > ? ? ? ? ? ? ? } > ? ? ? ? ? ?} > ? ? ? ? } > ? ? ?} > > ? ADVANCED EXAMPLE: A simple utility to execute a query and write values as > a comma delimited file. > > ? ? ?//This is the existing way of doing it > ? ? ?//Lines of code: 55 > ? ? ?package com.vci.projectcoin.using; > > ? ? ?import java.sql.*; > ? ? ?import java.io.*; > > ? ? ?public class AdvancedExample { > ? ? ? ? final static String EOL = System.getProperty("line.separator"); > > ? ? ? ? //Command Line: [] > ? ? ? ? static public void main(String []args) throws SQLException, > FileNotFoundException { > ? ? ? ? ? ?String url = args[0]; > ? ? ? ? ? ?String sql = args[1]; > ? ? ? ? ? ?PrintWriter out = new PrintWriter(args.length > 2 ? new > FileOutputStream(args[2]) : System.out); > ? ? ? ? ? ?try { > ? ? ? ? ? ? ? Connection conn = DriverManager.getConnection(url); > ? ? ? ? ? ? ? try { > ? ? ? ? ? ? ? ? ?Statement query = > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > ResultSet.CONCUR_READ_ONLY); > ? ? ? ? ? ? ? ? ?try { > ? ? ? ? ? ? ? ? ? ? ResultSet results = query.executeQuery(sql); > ? ? ? ? ? ? ? ? ? ? try { > ? ? ? ? ? ? ? ? ? ? ? ?ResultSetMetaData meta = results.getMetaData(); > ? ? ? ? ? ? ? ? ? ? ? ?int colCount = meta.getColumnCount(); > ? ? ? ? ? ? ? ? ? ? ? ?while (results.next()) { > ? ? ? ? ? ? ? ? ? ? ? ? ? for (int index = 1; index <= colCount; index++) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR ?|| > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? colType == Types.NCHAR || > colType == Types.NVARCHAR ? ? || colType == Types.VARCHAR; > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?System.out.append(results.getString(index)); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (index < colCount) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(','); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? } finally { > ? ? ? ? ? ? ? ? ? ? ? ?results.close(); > ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? ? ? ? query.close(); > ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? } finally { > ? ? ? ? ? ? ? ? ?conn.close(); > ? ? ? ? ? ? ? } > ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? out.close(); > ? ? ? ? ? ?} > ? ? ? ? } > ? ? ?} > > ? ? ?//This is the proposed way of doing it > ? ? ?//This proposal gets rid of the finally clean up per object. ?It lets > one write robust resource clean-up code without a lot of effort. > ? ? ?//Lines of code: 43 > ? ? ?package com.vci.projectcoin.using; > > ? ? ?import java.sql.*; > ? ? ?import java.io.*; > > ? ? ?public class AdvancedExample { > ? ? ? ? final static String EOL = System.getProperty("line.separator"); > > ? ? ? ? //Command Line: [] > ? ? ? ? static public void main(String []args) throws SQLException, > FileNotFoundException { > ? ? ? ? ? ?String url = args[0]; > ? ? ? ? ? ?String sql = args[1]; > ? ? ? ? ? ?try (PrintWriter out = new PrintWriter(args.length > 2 ? new > FileOutputStream(args[2]) : System.out)) { > ? ? ? ? ? ? ? try (Connection conn = DriverManager.getConnection(url)) { > ? ? ? ? ? ? ? ? ?try (Statement query = > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > ResultSet.CONCUR_READ_ONLY)) { > ? ? ? ? ? ? ? ? ? ? try (ResultSet results = query.executeQuery(sql)) { > ? ? ? ? ? ? ? ? ? ? ? ?ResultSetMetaData meta = results.getMetaData(); > ? ? ? ? ? ? ? ? ? ? ? ?int colCount = meta.getColumnCount(); > ? ? ? ? ? ? ? ? ? ? ? ?while (results.next()) { > ? ? ? ? ? ? ? ? ? ? ? ? ? for (int index = 1; index <= colCount; index++) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR || > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == > Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?System.out.append(results.getString(index)); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (index < colCount) { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(','); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else { > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println(); > ? ? ? ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? } > ? ? ? ? ? ?} > ? ? ? ? } > ? ? ?} > > ? ? ?//This is an additional syntactic sugar proposal, allowing multiple > objects to be allocated inside one try block. ?The compiler converts all > three programs into the same bytecode > ? ? ?//This proposal gets rid of the additional indentation level and > closing brace per object. ?It further minimize the clean-up boiler-plate, > allowing the point of the program logic to be clearer. > ? ? ?//Lines of code: 38 > ? ? ?package com.vci.projectcoin.using; > > ? ? ?import java.sql.*; > ? ? ?import java.io.*; > > ? ? ?public class AdvancedExample { > ? ? ? ? final static String EOL = System.getProperty("line.separator"); > > ? ? ? ? //Command Line: [] > ? ? ? ? static public void main(String []args) throws SQLException, > FileNotFoundException { > ? ? ? ? ? ?String url = args[0]; > ? ? ? ? ? ?String sql = args[1]; > ? ? ? ? ? ?try (PrintWriter out = new PrintWriter(args.length > 2 ? new > FileOutputStream(args[2]) : System.out), > ? ? ? ? ? ? ? ? Statement query = > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > ResultSet.CONCUR_READ_ONLY), > ? ? ? ? ? ? ? ? ResultSet results = query.executeQuery(sql)) { > ? ? ? ? ? ? ? ResultSetMetaData meta = results.getMetaData(); > ? ? ? ? ? ? ? int colCount = meta.getColumnCount(); > ? ? ? ? ? ? ? while (results.next()) { > ? ? ? ? ? ? ? for (int index = 1; index <= colCount; index++) { > ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); > ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR ?|| colType == > Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == Types.NCHAR > || colType == Types.NVARCHAR ? ? || colType == Types.VARCHAR; > ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ?System.out.append(results.getString(index)); > ? ? ? ? ? ? ? ? ?if (quoted) { > ? ? ? ? ? ? ? ? ? ? System.out.append('"'); > ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ? ?if (index < colCount) { > ? ? ? ? ? ? ? ? ? ? System.out.print(','); > ? ? ? ? ? ? ? ? ?} else { > ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); > ? ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? System.out.println(); > ? ? ? ? ? ? ? } > ? ? ? ? ? ?} > ? ? ? ? } > ? ? ?} > > DETAILS > ? The specification requires that the object in the try () block have a > "close()" method. ?Wether the method throws any or no exception, or if it > returns a value or no value does not matter. ?The proposal is not trying to > introduce any new intelligence into the try finally clause, it is just > syntactic sugar to minimize simple resource clean-up code. > > ? SPECIFICATION: > ? ? ?The "try" keyword will have an overloaded meaning > > ? ? ?CASE 1 > ? ? ?------ > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); > ? ? ?try { > ? ? ? ? //work gets done here > ? ? ?} finally { > ? ? ? ? value.close(); > ? ? ?} > > ? ? ?CASE 2 > ? ? ?------ > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} finally { > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); > ? ? ?try { > ? ? ? ? //work gets done here > ? ? ?} finally { > ? ? ? ? value.close(); > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?CASE 3 > ? ? ?------ > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} catch (Exception ex) { > ? ? ? ? //exception handling code > ? ? ?} finally { > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); > ? ? ?try { > ? ? ? ? //work gets done here > ? ? ?} catch (Exception ex) { > ? ? ? ? //exception handling code > ? ? ?} finally { > ? ? ? ? value.close(); > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?CASE 4 > ? ? ?------ > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > ? ? ?try { > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > ? ? ? ? try { > ? ? ? ? ? ?Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > ? ? ? ? ? ?try { > ? ? ? ? ? ? ? //work gets done here > ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? value3.close(); > ? ? ? ? ? ?} > ? ? ? ? } finally { > ? ? ? ? ? ?value2.close(); > ? ? ? ? } > ? ? ?} finally { > ? ? ? ? value1.close(); > ? ? ?} > > ? ? ?CASE 5 > ? ? ?------ > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} finally { > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > ? ? ?try { > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > ? ? ? ? try { > ? ? ? ? ? ?Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > ? ? ? ? ? ?try { > ? ? ? ? ? ? ? //work gets done here > ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? value3.close(); > ? ? ? ? ? ?} > ? ? ? ? } finally { > ? ? ? ? ? ?value2.close(); > ? ? ? ? } > ? ? ?} finally { > ? ? ? ? value1.close(); > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?CASE 6 > ? ? ?------ > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) { > ? ? ? ? //work gets done here > ? ? ?} catch (Exception ex) { > ? ? ? ? //exception handling code > ? ? ?} finally { > ? ? ? ? //additional clean-up code > ? ? ?} > > ? ? ?Will be syntactic sugar for: > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > ? ? ?try { > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > ? ? ? ? try { > ? ? ? ? ? ?Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > ? ? ? ? ? ?try { > ? ? ? ? ? ? ? //work gets done here > ? ? ? ? ? ?} finally { > ? ? ? ? ? ? ? value3.close(); > ? ? ? ? ? ?} > ? ? ? ? } finally { > ? ? ? ? ? ?value2.close(); > ? ? ? ? } > ? ? ?} catch (Exception ex) { > ? ? ? ? //exception handling code > ? ? ?} finally { > ? ? ? ? value1.close(); > ? ? ? ? //additional clean-up code > ? ? ?} > > ? COMPILATION: The SPECIFICATION section above shows the desugaring for > each case. ?Byte code would be identical to the desugared constructs. > > ? TESTING: Byte code comparison of common code constructs. ?If the byte > code is not identical to the desugared version, test fails. > > ? LIBRARY SUPPORT: No. > > ? REFLECTIVE APIS: No. > > ? OTHER CHANGES: No. > > ? MIGRATION: For each case in the SPECIFICATION section, convert the > existing code to the syntactic sugar proposal. > > > COMPATIBILITY > > ? BREAKING CHANGES: None. > > ? EXISTING PROGRAMS: Compile accepts both existing and new forms of the > "try" statement. ?Byte code does not change. > > REFERENCES > > ? EXISTING BUGS: None > > > -- > Roger Hernandez > > From neal at gafter.com Mon Mar 2 23:33:17 2009 From: neal at gafter.com (Neal Gafter) Date: Mon, 2 Mar 2009 23:33:17 -0800 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <49ACCE49.8030103@sun.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> <49ACCE49.8030103@sun.com> Message-ID: <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> On Mon, Mar 2, 2009 at 10:29 PM, Joseph D. Darcy wrote: >> MAJOR DISADVANTAGE: >> >> One-time implementation cost for adding the features to the compiler. >> Longer language specification in describing the behavior. >> > > What sort of poor programming practices could this feature encourage or > enable? I don't see any, but perhaps I'm shortsighted. >> The type system is affected as follows: For the purpose of type >> checking, a catch parameter declared with a disjunction has type >> lub(t1, t2, ...) [JLS3 15.12.2.5]. > > In terms of finding the members of the type, it is good existing concepts in > the JLS can be used. > > What happens if someone writes > > ? catch(final IOException | SomeSubclassOfIOException e) {...} > > In other words, is it legal to have subclasses of a caught exception listed > too? I don't really care one way or the other. As written, yes, it is allowed and means the same thing as the supertype alone. >> To avoid the need to add support for general disjunctive types, but >> leaving open the possibility of a future extension along these lines, >> a catch parameter whose type has more than one disjunct is required to >> be declared final. >> > > I think that is a fine compromise that keep the current feature smaller > while allowing room for a broader feature later. > > Some worked examples of the sets of thrown exceptions types under various > tricky code samples would help clarify the data flow algorithm for me. Sure, I can do that. Do you think that should go in the specification? >> A catch clause is currently compiled (before this change) to an entry >> in an exception table that specifies the type of the exception and the >> address of the code for the catch body. To generate code for this new >> construct, the compiler would generate an entry in the exception table >> for each type in the exception parameter's list of types. >> > > Interesting; so there would be no code duplication even in the class files. Correct. That's what the current prototype (in the BGGA compiler) does for this construct. > How could the increased exception precision be maintained will still allow > programs such as the one above to compile? I don't think it can without making rather complex rules, but I'll think about it more. However, one could take only the multicatch part of this proposal and not the final/rethrow part, and then I believe one could specify it without there being a breaking change. From neal at gafter.com Mon Mar 2 23:43:27 2009 From: neal at gafter.com (Neal Gafter) Date: Mon, 2 Mar 2009 23:43:27 -0800 Subject: Proposal: Block Expressions for Java In-Reply-To: <49ACC44A.1040609@sun.com> References: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> <15e8b9d20902272130i3e52b349ta500f4b98accec01@mail.gmail.com> <49ACC44A.1040609@sun.com> Message-ID: <15e8b9d20903022343k4d9a056el513c4b113e27f318@mail.gmail.com> On Mon, Mar 2, 2009 at 9:46 PM, Joseph D. Darcy wrote: >> Meaning of Expressions: The specification for a parenthesized >> expression should be modified to describe its new execution semantics: >> The block statements (if any) are executed in sequence, from left to >> right, exactly as in a block statement. ?The result of the >> parenthesized expression is the result of evaluating its >> subexpression. >> > > So what about return, break, and continue statements inside the > BlockStatements? They behave as already specified in the JLS. >> Compilation is straightforward, with one minor exception (no pun >> intended). ?The compiler must arrange the generated code such that the >> stack is empty at the beginning of any try statement that can complete >> normally when the try statement is embedded within a parenthesized >> expression. ?That is because the VM empties the stack when exceptions >> are handled. ?This can be accommodated by spilling values from the >> stack into VM locals. >> > > That doesn't necessarily sound minor! It is because (1) it will be extremely rare in practice, and (2) even when it happens, the number of additional bytecodes to spill and unspill the registers is small. I prototyped something close to this spilling strategy when I implemented stackmaps: I added an option that causes the stack to be empty at every basic block boundary (which in expressions occurs because of ?:). It caused an additional fraction of a percent in code size. This would have an even smaller impact. From neal at gafter.com Mon Mar 2 23:54:14 2009 From: neal at gafter.com (Neal Gafter) Date: Mon, 2 Mar 2009 23:54:14 -0800 Subject: Simple Resource Clean-up In-Reply-To: References: <15e8b9d20903022323k17c3f1afo9919c311070b17be@mail.gmail.com> Message-ID: <15e8b9d20903022354y62f10866t8f403767d22a874f@mail.gmail.com> Just to make sure I understand, in your specification, if an exception is thrown from the try block, and then another exception is thrown from the close() method, the one from the close() is the one that propogates out? On Mon, Mar 2, 2009 at 11:43 PM, Roger Hernandez wrote: > Sorry I meant to take that part out, since I saw the comments from the > previous proposal.? The way I envision it working is in a way how C++ > template instantiation works.? The compiler just requires that a class have > an accessible "close()" function, it should not care what interface or class > it comes from.? That way it can throw any exception type. > - Show quoted text - > > On Tue, Mar 3, 2009 at 2:23 AM, Neal Gafter wrote: >> >> You say "The object being created must implement the Closeable >> interface." ?But java.sql.Statement, to pick one example, cannot be >> made to implement that interface because the exception signatures are >> not compatible. >> >> I'll let others comment about issues with exception handling in the >> translation. >> >> -Neal >> >> On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez >> wrote: >> > I saw how the previous Automatic Resource Management proposal got torn >> > to >> > pieces but I feel strongly enough about this issue to post a similar >> > proposal. >> > >> > Some points: >> > >> > I am not a programming language designer. ?I have very little experience >> > with byte code and with design and implementation of compilers. ?What I >> > do >> > have is many years of experience in writing code for large business >> > applications, both in house-custom programs and shrink-wrapped products >> > sold >> > to customers. >> > >> > About 1/3 of the Java code I write contributes almost nothing to the >> > functionality or flexibility of the program. ?It is composed of very >> > simple >> > and very repetitive resource clean-up code. ?JDBC code is an especially >> > bad >> > case. ?I know we should be using JDO or JPA, but: 1) most of the Java >> > database code in existence is using JDBC to some extent or another, 2) >> > for >> > the kind of processing our software does with large datasets having >> > hundreds >> > of megabytes of row data and millions of rows per account per month, >> > custom >> > JDBC code still beats the other solutions in memory utilization and >> > throughput. >> > >> > In most business code we don't do complex exception processing. ?If we >> > get a >> > exception we rollback the transaction and unroll the stack until we >> > reach >> > some program level error handler that logs the error for some >> > administrator >> > to review at a later date. ?So if this proposal is not applicable to >> > complex >> > error handling scenarios, that is fine. ?Taking care of the simple >> > scenarios >> > will still get rid of most of that 1/3 of the code I write, allowing me >> > to >> > concentrate on the actual program logic, not the resource clean-up >> > noise. >> > >> > I also program quite a bit in C++ and C# and when I work in Java I >> > sorely >> > miss RAII (Resource Acquisition Is Initialization) and the "using" >> > statement >> > respectively. >> > >> > At the end of the day, what I would like is a solution to minimize all >> > the >> > resource clean-up boiler plate. >> > >> > >> > ----------------------------------------------------------------------------------------- >> > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >> > >> > ? AUTHOR: Roger Hernandez, rogerh at velocityconsultinginc.com >> > >> > OVERVIEW >> > >> > ? FEATURE SUMMARY: Syntactic sugar for simple cases of the common >> > new/try/finally/close language idiom. ?The object being created must >> > implement the Closeable interface. >> > >> > ? MAJOR ADVANTAGE: Significantly reduces lines of code when working with >> > objects that encapsulate external resources that should be closed as >> > soon as >> > possible. ?Examples are Stream, Reader, Writer classes in java.io, and >> > Connection, Statement, PreparedStatement, ResultSet in java.sql.*. >> > >> > ? MAJOR BENEFIT: It allows writing code that uses these kinds of object >> > to >> > more clearly express the both the lifetime of the utilization of each >> > resource, and allows the logic flow of the code to be more visible. >> > >> > ? MAJOR DISADVANTAGE: Either a new keyword, or an additional overloaded >> > meaning on an existing keyword. >> > >> > ? ALTERNATIVES: You can always use the standard idiom: SomeType val = >> > new >> > val(...); try { ... } finally { val.close(); } >> > >> > EXAMPLES >> > >> > ? SIMPLE EXAMPLE: ?A simple Java version of the command line utility >> > "tee". >> > ? ? ?//This is the existing way of doing it. >> > ? ? ?//Lines of code: 19 >> > ? ? ?package com.vci.projectcoin.using; >> > >> > ? ? ?import java.io.*; >> > >> > ? ? ?public class SimpleExample { >> > >> > ? ? ? ? public static void main(String[] args) throws IOException { >> > ? ? ? ? ? ?byte []buffer = new byte[1024]; >> > ? ? ? ? ? ?FileOutputStream out = new FileOutputStream(args[0]); >> > ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? for (int count; (count = System.in.read(buffer)) != -1;) { >> > ? ? ? ? ? ? ? ? ?out.write(buffer, 0, count); >> > ? ? ? ? ? ? ? ? ?System.out.write(buffer, 0, count); >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? out.close(); >> > ? ? ? ? ? ?} >> > ? ? ? ? } >> > ? ? ?} >> > >> > ? ? ?//This is the proposed way of doing it, the compiler converts the >> > syntactic sugar into the same byte codes >> > ? ? ?//I am adding a new use to the the "try" keyword to avoid adding >> > more >> > to the language, but it would work >> > ? ? ?//just a well with a "using" keyword. >> > ? ? ?//Lines of code: 16 >> > ? ? ?package com.vci.projectcoin.using; >> > >> > ? ? ?import java.io.*; >> > >> > ? ? ?public class SimpleExample { >> > >> > ? ? ? ? public static void main(String[] args) throws IOException { >> > ? ? ? ? ? ?byte []buffer = new byte[1024]; >> > ? ? ? ? ? ?try (FileOutputStream out = new FileOutputStream(args[0])) { >> > ? ? ? ? ? ? ? for (int count; (count = System.in.read(buffer)) != -1;) { >> > ? ? ? ? ? ? ? ? ?out.write(buffer, 0, count); >> > ? ? ? ? ? ? ? ? ?System.out.write(buffer, 0, count); >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ?} >> > ? ? ? ? } >> > ? ? ?} >> > >> > ? ADVANCED EXAMPLE: A simple utility to execute a query and write values >> > as >> > a comma delimited file. >> > >> > ? ? ?//This is the existing way of doing it >> > ? ? ?//Lines of code: 55 >> > ? ? ?package com.vci.projectcoin.using; >> > >> > ? ? ?import java.sql.*; >> > ? ? ?import java.io.*; >> > >> > ? ? ?public class AdvancedExample { >> > ? ? ? ? final static String EOL = System.getProperty("line.separator"); >> > >> > ? ? ? ? //Command Line: [] >> > ? ? ? ? static public void main(String []args) throws SQLException, >> > FileNotFoundException { >> > ? ? ? ? ? ?String url = args[0]; >> > ? ? ? ? ? ?String sql = args[1]; >> > ? ? ? ? ? ?PrintWriter out = new PrintWriter(args.length > 2 ? new >> > FileOutputStream(args[2]) : System.out); >> > ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? Connection conn = DriverManager.getConnection(url); >> > ? ? ? ? ? ? ? try { >> > ? ? ? ? ? ? ? ? ?Statement query = >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, >> > ResultSet.CONCUR_READ_ONLY); >> > ? ? ? ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? ? ? ? ResultSet results = query.executeQuery(sql); >> > ? ? ? ? ? ? ? ? ? ? try { >> > ? ? ? ? ? ? ? ? ? ? ? ?ResultSetMetaData meta = results.getMetaData(); >> > ? ? ? ? ? ? ? ? ? ? ? ?int colCount = meta.getColumnCount(); >> > ? ? ? ? ? ? ? ? ? ? ? ?while (results.next()) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? for (int index = 1; index <= colCount; >> > index++) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR ?|| >> > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? colType == Types.NCHAR || >> > colType == Types.NVARCHAR ? ? || colType == Types.VARCHAR; >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > >> > ?System.out.append(results.getString(index)); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (index < colCount) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(','); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? ? ? ? } >> > ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? } finally { >> > ? ? ? ? ? ? ? ? ? ? ? ?results.close(); >> > ? ? ? ? ? ? ? ? ? ? } >> > ? ? ? ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? ? ? ? query.close(); >> > ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? } finally { >> > ? ? ? ? ? ? ? ? ?conn.close(); >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? out.close(); >> > ? ? ? ? ? ?} >> > ? ? ? ? } >> > ? ? ?} >> > >> > ? ? ?//This is the proposed way of doing it >> > ? ? ?//This proposal gets rid of the finally clean up per object. ?It >> > lets >> > one write robust resource clean-up code without a lot of effort. >> > ? ? ?//Lines of code: 43 >> > ? ? ?package com.vci.projectcoin.using; >> > >> > ? ? ?import java.sql.*; >> > ? ? ?import java.io.*; >> > >> > ? ? ?public class AdvancedExample { >> > ? ? ? ? final static String EOL = System.getProperty("line.separator"); >> > >> > ? ? ? ? //Command Line: [] >> > ? ? ? ? static public void main(String []args) throws SQLException, >> > FileNotFoundException { >> > ? ? ? ? ? ?String url = args[0]; >> > ? ? ? ? ? ?String sql = args[1]; >> > ? ? ? ? ? ?try (PrintWriter out = new PrintWriter(args.length > 2 ? new >> > FileOutputStream(args[2]) : System.out)) { >> > ? ? ? ? ? ? ? try (Connection conn = DriverManager.getConnection(url)) { >> > ? ? ? ? ? ? ? ? ?try (Statement query = >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, >> > ResultSet.CONCUR_READ_ONLY)) { >> > ? ? ? ? ? ? ? ? ? ? try (ResultSet results = query.executeQuery(sql)) { >> > ? ? ? ? ? ? ? ? ? ? ? ?ResultSetMetaData meta = results.getMetaData(); >> > ? ? ? ? ? ? ? ? ? ? ? ?int colCount = meta.getColumnCount(); >> > ? ? ? ? ? ? ? ? ? ? ? ?while (results.next()) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? for (int index = 1; index <= colCount; >> > index++) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR || >> > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType >> > == >> > Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > >> > ?System.out.append(results.getString(index)); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (index < colCount) { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(','); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else { >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); >> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? ? ? ? } >> > ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println(); >> > ? ? ? ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ? ? } >> > ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ?} >> > ? ? ? ? } >> > ? ? ?} >> > >> > ? ? ?//This is an additional syntactic sugar proposal, allowing multiple >> > objects to be allocated inside one try block. ?The compiler converts all >> > three programs into the same bytecode >> > ? ? ?//This proposal gets rid of the additional indentation level and >> > closing brace per object. ?It further minimize the clean-up >> > boiler-plate, >> > allowing the point of the program logic to be clearer. >> > ? ? ?//Lines of code: 38 >> > ? ? ?package com.vci.projectcoin.using; >> > >> > ? ? ?import java.sql.*; >> > ? ? ?import java.io.*; >> > >> > ? ? ?public class AdvancedExample { >> > ? ? ? ? final static String EOL = System.getProperty("line.separator"); >> > >> > ? ? ? ? //Command Line: [] >> > ? ? ? ? static public void main(String []args) throws SQLException, >> > FileNotFoundException { >> > ? ? ? ? ? ?String url = args[0]; >> > ? ? ? ? ? ?String sql = args[1]; >> > ? ? ? ? ? ?try (PrintWriter out = new PrintWriter(args.length > 2 ? new >> > FileOutputStream(args[2]) : System.out), >> > ? ? ? ? ? ? ? ? Statement query = >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, >> > ResultSet.CONCUR_READ_ONLY), >> > ? ? ? ? ? ? ? ? ResultSet results = query.executeQuery(sql)) { >> > ? ? ? ? ? ? ? ResultSetMetaData meta = results.getMetaData(); >> > ? ? ? ? ? ? ? int colCount = meta.getColumnCount(); >> > ? ? ? ? ? ? ? while (results.next()) { >> > ? ? ? ? ? ? ? for (int index = 1; index <= colCount; index++) { >> > ? ? ? ? ? ? ? ? ?int colType = meta.getColumnType(index); >> > ? ? ? ? ? ? ? ? ?boolean quoted = colType == Types.CHAR ?|| colType == >> > Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == >> > Types.NCHAR >> > || colType == Types.NVARCHAR ? ? || colType == Types.VARCHAR; >> > ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ?System.out.append(results.getString(index)); >> > ? ? ? ? ? ? ? ? ?if (quoted) { >> > ? ? ? ? ? ? ? ? ? ? System.out.append('"'); >> > ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? ? ?if (index < colCount) { >> > ? ? ? ? ? ? ? ? ? ? System.out.print(','); >> > ? ? ? ? ? ? ? ? ?} else { >> > ? ? ? ? ? ? ? ? ? ? System.out.print(EOL); >> > ? ? ? ? ? ? ? ? ?} >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ? ? System.out.println(); >> > ? ? ? ? ? ? ? } >> > ? ? ? ? ? ?} >> > ? ? ? ? } >> > ? ? ?} >> > >> > DETAILS >> > ? The specification requires that the object in the try () block have a >> > "close()" method. ?Wether the method throws any or no exception, or if >> > it >> > returns a value or no value does not matter. ?The proposal is not trying >> > to >> > introduce any new intelligence into the try finally clause, it is just >> > syntactic sugar to minimize simple resource clean-up code. >> > >> > ? SPECIFICATION: >> > ? ? ?The "try" keyword will have an overloaded meaning >> > >> > ? ? ?CASE 1 >> > ? ? ?------ >> > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { >> > ? ? ? ? //work gets done here >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? //work gets done here >> > ? ? ?} finally { >> > ? ? ? ? value.close(); >> > ? ? ?} >> > >> > ? ? ?CASE 2 >> > ? ? ?------ >> > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { >> > ? ? ? ? //work gets done here >> > ? ? ?} finally { >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? //work gets done here >> > ? ? ?} finally { >> > ? ? ? ? value.close(); >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?CASE 3 >> > ? ? ?------ >> > ? ? ?try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { >> > ? ? ? ? //work gets done here >> > ? ? ?} catch (Exception ex) { >> > ? ? ? ? //exception handling code >> > ? ? ?} finally { >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?ClassWithCloseMethod value = new ClassWithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? //work gets done here >> > ? ? ?} catch (Exception ex) { >> > ? ? ? ? //exception handling code >> > ? ? ?} finally { >> > ? ? ? ? value.close(); >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?CASE 4 >> > ? ? ?------ >> > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), >> > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), >> > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) >> > { >> > ? ? ? ? //work gets done here >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); >> > ? ? ? ? try { >> > ? ? ? ? ? ?Class3WithCloseMethod value3 = new >> > Class3WithCloseMethod(...); >> > ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? //work gets done here >> > ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? value3.close(); >> > ? ? ? ? ? ?} >> > ? ? ? ? } finally { >> > ? ? ? ? ? ?value2.close(); >> > ? ? ? ? } >> > ? ? ?} finally { >> > ? ? ? ? value1.close(); >> > ? ? ?} >> > >> > ? ? ?CASE 5 >> > ? ? ?------ >> > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), >> > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), >> > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) >> > { >> > ? ? ? ? //work gets done here >> > ? ? ?} finally { >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); >> > ? ? ? ? try { >> > ? ? ? ? ? ?Class3WithCloseMethod value3 = new >> > Class3WithCloseMethod(...); >> > ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? //work gets done here >> > ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? value3.close(); >> > ? ? ? ? ? ?} >> > ? ? ? ? } finally { >> > ? ? ? ? ? ?value2.close(); >> > ? ? ? ? } >> > ? ? ?} finally { >> > ? ? ? ? value1.close(); >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?CASE 6 >> > ? ? ?------ >> > ? ? ?try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), >> > ? ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), >> > ? ? ? ? ? Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) >> > { >> > ? ? ? ? //work gets done here >> > ? ? ?} catch (Exception ex) { >> > ? ? ? ? //exception handling code >> > ? ? ?} finally { >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? ? ?Will be syntactic sugar for: >> > ? ? ?Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); >> > ? ? ?try { >> > ? ? ? ? Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); >> > ? ? ? ? try { >> > ? ? ? ? ? ?Class3WithCloseMethod value3 = new >> > Class3WithCloseMethod(...); >> > ? ? ? ? ? ?try { >> > ? ? ? ? ? ? ? //work gets done here >> > ? ? ? ? ? ?} finally { >> > ? ? ? ? ? ? ? value3.close(); >> > ? ? ? ? ? ?} >> > ? ? ? ? } finally { >> > ? ? ? ? ? ?value2.close(); >> > ? ? ? ? } >> > ? ? ?} catch (Exception ex) { >> > ? ? ? ? //exception handling code >> > ? ? ?} finally { >> > ? ? ? ? value1.close(); >> > ? ? ? ? //additional clean-up code >> > ? ? ?} >> > >> > ? COMPILATION: The SPECIFICATION section above shows the desugaring for >> > each case. ?Byte code would be identical to the desugared constructs. >> > >> > ? TESTING: Byte code comparison of common code constructs. ?If the byte >> > code is not identical to the desugared version, test fails. >> > >> > ? LIBRARY SUPPORT: No. >> > >> > ? REFLECTIVE APIS: No. >> > >> > ? OTHER CHANGES: No. >> > >> > ? MIGRATION: For each case in the SPECIFICATION section, convert the >> > existing code to the syntactic sugar proposal. >> > >> > >> > COMPATIBILITY >> > >> > ? BREAKING CHANGES: None. >> > >> > ? EXISTING PROGRAMS: Compile accepts both existing and new forms of the >> > "try" statement. ?Byte code does not change. >> > >> > REFERENCES >> > >> > ? EXISTING BUGS: None >> > >> > >> > -- >> > Roger Hernandez >> > >> > > > > > -- > Roger Hernandez > From jjb at google.com Tue Mar 3 00:18:03 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 00:18:03 -0800 Subject: Simple Resource Clean-up In-Reply-To: References: Message-ID: <17b2302a0903030018p3736108eq9e3baf3ce5ab4b5b@mail.gmail.com> Roger, On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez wrote: > I saw how the previous Automatic Resource Management proposal got torn to > pieces That's not quite fair. Only one person objected, and I had good responses to all of his objections. So I believe the proposal is alive and well. Others have informed me (off list) that they see Automatic Resource Management as perhaps the most valuable language change that we could introduce for Java 7. Regards, Josh From rssh at gradsoft.com.ua Tue Mar 3 00:19:33 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Tue, 3 Mar 2009 10:19:33 +0200 (EET) Subject: PROPOSAL: Multiline strings In-Reply-To: <49ACCF70.20908@sun.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> <49ACCF70.20908@sun.com> Message-ID: <32752b516ddfea7aedb868343fce211c.squirrel@wmail.gradsoft.ua> > rssh at gradsoft.com.ua wrote: >> 1. Since we have non-empty discussion, I setup wiki with current >> proposal >> ('new string literals instead multiline strings (?)') >> >> http://redmine.gradsoft.ua/wiki/java7stringliterals >> and will try to track all changes as issues. >> > > The Project Coin mailing list is the place for discussion of proposals > submitted to Project Coin! > Yes, of course. Enumerated list of issues just help me to organize materials for discussions here ;) > -Joe > > From scolebourne at joda.org Tue Mar 3 00:54:39 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 03 Mar 2009 08:54:39 +0000 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> <49ACCE49.8030103@sun.com> <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> Message-ID: <49ACF04F.60101@joda.org> Neal Gafter wrote: >> What happens if someone writes >> >> catch(final IOException | SomeSubclassOfIOException e) {...} >> >> In other words, is it legal to have subclasses of a caught exception listed >> too? > > I don't really care one way or the other. As written, yes, it is > allowed and means the same thing as the supertype alone. I would continue to allow this in the spec. It means that if someone refactors exceptions changing the hierarchy, then another part of the code with a multi-catch will continue to compile and have the same meaning. >> How could the increased exception precision be maintained will still allow >> programs such as the one above to compile? > > I don't think it can without making rather complex rules, but I'll > think about it more. > > However, one could take only the multicatch part of this proposal and > not the final/rethrow part, and then I believe one could specify it > without there being a breaking change. I would prefer to see them added to Project Coin as two separate proposals. (I have some usability concerns with rethrow, but am OK with multi-catch) Stephen From brucechapman at paradise.net.nz Tue Mar 3 01:21:21 2009 From: brucechapman at paradise.net.nz (Bruce Chapman) Date: Tue, 03 Mar 2009 22:21:21 +1300 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: References: Message-ID: <49ACF691.5090104@paradise.net.nz> My 2 cents: This partially covers the need for type aliases, but not for generic types (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4983159), if we are going to introduce aliases it should cover the generic case as well. An alternative syntax to avoid the 'as' keyword could be "import Sqldate = java.sql.Date;" Either syntax could probably cover the generic type alias case as well, however I am not sure if an "import" statement is the right way to do that. I liked your examples, some are very compelling. An alternative mechanism that preserves the simple names might be to alias the package rather than aliasing the type. eg import ju=java.util; // or import package ju=java.util; import js=java.sql; js.Date date = new js.Date(new ju.Date); That gets further away from solving the generics alias issue, which might be a good thing : it leaves it easier to do a complete type aliases solution as a separate issue. (IS anyone working on a type aliases proposal for coin?) Bruce Phil Varner wrote: > Import Aliases for Classes and Static Methods > > http://docs.google.com/Doc?id=dgx74dt7_19dxnspbhj > > AUTHOR: Phil Varner > > OVERVIEW > > FEATURE SUMMARY: The import aliases feature allows a user to provide > an alias underwhich an imported class or statically imported method > must be referred to in the containing source file. An example of the > use of this feature is "import java.sql.Date as SqlDate;" > > MAJOR ADVANTAGE: This feature would allow easier use of multiple > classes which have the same name but different packages to be used in > the same source file. > > MAJOR BENEFIT: This will prevent the necessity of fully-qualifiying > all class references when there is a name collision, leading to more > readable code. > > MAJOR DISADVANTAGE: This will introduce an extra level of indirection > when determing the source of a given class or method, introduce a new > keyword 'as', and will require changes to IDE code completion > functionality. > > ALTERNATIVES: In some cases, a nested class can be created which > trivially derives a class involved in the name collision. For a > method, a wrapper method can be created in the source file. > > EXAMPLES > > SIMPLE EXAMPLE: > > Example #1, duplicate class name > > Current code: > > new java.sql.Date(new java.util.Date()); > > New code: > > import java.sql.Date as SqlDate; > import java.util.Date as UtilDate; > > new SqlDate(new UtilDate()); > > Example #2, statically imported method alias > > Current code: > > import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName; > > public static int mrlacsmn(final int arg1, final String arg2){ > return myReallyLongAndComplicatedStaticMethodName(arg1, arg2); > } > > mrlacsmn(1, a); > > New code: > > import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName > as mrlacsmn; > > mrlacsmn(1, a); > > ADVANCED EXAMPLE: > > Example #3 > > Translation of persistent formats between similar APIs. > > In many domains, it is not uncommon to have two different APIs with > classes with the same name. For example, in a production rules API, > one may have classes "RuleSet" and "Rule". When attempting to use the > API to translate between these these APIs, it must be decided that one > is fully-qualified and one is not. This can lead to code like: > > com.example.foo.bar.sdk.RuleSet srcRuleSet = ...; > com.example.foo.bar.sdk2.RuleSet dstRuleSet = new > com.example.foo.bar.sdk2.RuleSet(); > migrate(srcRuleSet, dstRuleSet); > ... > > private static void migrate(com.example.foo.bar.sdk.RuleSet srcRuleSet, > com.example.foo.bar.sdk2.RuleSet dstRuleSet){ > ... > } > > Note that it is good practice here not to import either class because > it is too easy to accidentally misuse constants and static methods. > > With the 'as' syntax, one could instead write the far less verbose and > more readible: > > import com.example.foo.bar.sdk.RuleSet as SrcRuleSet; > import com.example.foo.bar.sdk2.RuleSet as DstRuleSet; > > ... > > SrcRuleSet srcRuleSet = ...; > DstRuleSet destRuleSet = new DstRuleSet(); > migrate(srcRuleSet, dstRuleSet); > > ... > > private static void migrate(SrcRuleSet srcRuleSet, > DstRuleSet dstRuleSet){ > ... > } > > Example #4 > > Ensuring correct method selection when static importing overloaded methods. > > Current code: > import static org.testng.Assert.assertEquals; > > public static int aeo(Object arg1, Object arg2){ > assertEquals(arg1, arg2); > } > > public static int aec(Collection arg1, Collection arg2){ > assertEquals(arg1, arg2); > } > > aeo(obj1, obj2); > aec(list1, list2); > > New code: > > import static org.testng.Assert.assertEquals(Object, Object) as aeo; > import static org.testng.Assert.assertEquals(Collection, Collection) as aec; > > aeo(obj1, obj2); > aec(list1, list2); > > Note: it is possible that this sort of method selection is beyond the > scope of a COIN proposal > > DETAILS > > SPECIFICATION: > > Grammar > > modification (JLS 3.9): > Keyword: > as > ... > > modification (JLS 7.5): > ImportDeclaration: > SingleTypeImportDeclarationWithAlias > SingleStaticImportDeclarationWithAlias > ... > > addition: > SingleTypeImportDeclarationWithAlias: > import TypeName as Identifier; > > addition: > SingleStaticImportDeclarationWithAlias: > import static TypeName . Identifier as Identifier; > > > Note that this would explicitly forbid wildcard imports from being aliased. > > There are no known effects on the type system or meaning of > expressions and statements in the Java Programming Language. > > COMPILATION: This feature would be a compile-time transform. It would > only affect the way in which a non-fully qualified class or method > name was resolved to a fully-qualified class or method name. > > TESTING: This change would be tested in a manner similar how how the > existing code which resolves the fully-qualified names of classes and > methods is tested. > > LIBRARY SUPPORT: No change > > REFLECTIVE APIS: No change > > OTHER CHANGES: No change > > MIGRATION: This change is backwards-compatible with existing code. > > COMPATIBILITY > > BREAKING CHANGES: No change > > EXISTING PROGRAMS: No change > > REFERENCES > > EXISTING BUGS: None at present > > URL FOR PROTOTYPE (optional): None at present > > From reinier at zwitserloot.com Tue Mar 3 02:06:34 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 11:06:34 +0100 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> <49ACCE49.8030103@sun.com> <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> Message-ID: <08E77F6F-6D7F-4A0F-B389-4851039220F0@zwitserloot.com> Maybe I'm making this too simple, but what if javac will treat all catch blocks of a type that isn't thrown by the try block as warnings instead of errors? That fixes Neal's Improved Exception Handling issue of not being 100% source compatible with java 6, no? I assume source compatibility where code that is clearly broken results in a warning in java 7 (but is still compiled with exactly the same semantics) whereas it was silently compiled by java 6 is only good news. Also, because in just about every other language on the JVM, checked exceptions can be thrown without being declared, I think this is a good idea in general, considering that java wants to be more interoperable with non-java JVM languages. To work around this issue now, you have to either wrap the call in a wrapper method that adds the exception to the throws list, or you have to create a dummy method that declares the throwable in the throws list but doesn't throw it, just so javac will stop refusing to compile your code. That's clearly a hack solution, and the elimination of it should be a good thing, even if you need to use a @SuppressWarnings instead, no? Should I write up a proposal for this? Should Neal add it to his proposal? Or is it just a horribly stupid idea? :) --Reinier Zwitserloot On Mar 3, 2009, at 08:33, Neal Gafter wrote: > On Mon, Mar 2, 2009 at 10:29 PM, Joseph D. Darcy > wrote: >>> MAJOR DISADVANTAGE: >>> >>> One-time implementation cost for adding the features to the >>> compiler. >>> Longer language specification in describing the behavior. >>> >> >> What sort of poor programming practices could this feature >> encourage or >> enable? > > I don't see any, but perhaps I'm shortsighted. > >>> The type system is affected as follows: For the purpose of type >>> checking, a catch parameter declared with a disjunction has type >>> lub(t1, t2, ...) [JLS3 15.12.2.5]. >> >> In terms of finding the members of the type, it is good existing >> concepts in >> the JLS can be used. >> >> What happens if someone writes >> >> catch(final IOException | SomeSubclassOfIOException e) {...} >> >> In other words, is it legal to have subclasses of a caught >> exception listed >> too? > > I don't really care one way or the other. As written, yes, it is > allowed and means the same thing as the supertype alone. > >>> To avoid the need to add support for general disjunctive types, but >>> leaving open the possibility of a future extension along these >>> lines, >>> a catch parameter whose type has more than one disjunct is >>> required to >>> be declared final. >>> >> >> I think that is a fine compromise that keep the current feature >> smaller >> while allowing room for a broader feature later. >> >> Some worked examples of the sets of thrown exceptions types under >> various >> tricky code samples would help clarify the data flow algorithm for >> me. > > Sure, I can do that. Do you think that should go in the > specification? > >>> A catch clause is currently compiled (before this change) to an >>> entry >>> in an exception table that specifies the type of the exception and >>> the >>> address of the code for the catch body. To generate code for this >>> new >>> construct, the compiler would generate an entry in the exception >>> table >>> for each type in the exception parameter's list of types. >>> >> >> Interesting; so there would be no code duplication even in the >> class files. > > Correct. That's what the current prototype (in the BGGA compiler) > does for this construct. > >> How could the increased exception precision be maintained will >> still allow >> programs such as the one above to compile? > > I don't think it can without making rather complex rules, but I'll > think about it more. > > However, one could take only the multicatch part of this proposal and > not the final/rethrow part, and then I believe one could specify it > without there being a breaking change. > From reinier at zwitserloot.com Tue Mar 3 02:09:11 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 11:09:11 +0100 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: <49ACF691.5090104@paradise.net.nz> References: <49ACF691.5090104@paradise.net.nz> Message-ID: <081BECAE-EF46-408D-AF76-7CA72CC62EE2@zwitserloot.com> An alternative that this proposal doesn't list is package imports. Something like: import java.util; import java.sql; new sql.Date(new util.Date()); --Reinier Zwitserloot On Mar 3, 2009, at 10:21, Bruce Chapman wrote: > My 2 cents: > > This partially covers the need for type aliases, but not for generic > types (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4983159), if > we are going to introduce aliases it should cover the generic case > as well. > > An alternative syntax to avoid the 'as' keyword could be > > "import Sqldate = java.sql.Date;" > > Either syntax could probably cover the generic type alias case as > well, > however I am not sure if an "import" statement is the right way to > do that. > > I liked your examples, some are very compelling. > > An alternative mechanism that preserves the simple names might be to > alias the package rather than aliasing the type. > eg > import ju=java.util; // or import package ju=java.util; > import js=java.sql; > > js.Date date = new js.Date(new ju.Date); > > > That gets further away from solving the generics alias issue, which > might be a good thing : it leaves it easier to do a complete type > aliases solution as a separate issue. (IS anyone working on a type > aliases proposal for coin?) > > Bruce > > > Phil Varner wrote: >> Import Aliases for Classes and Static Methods >> >> http://docs.google.com/Doc?id=dgx74dt7_19dxnspbhj >> >> AUTHOR: Phil Varner >> >> OVERVIEW >> >> FEATURE SUMMARY: The import aliases feature allows a user to provide >> an alias underwhich an imported class or statically imported method >> must be referred to in the containing source file. An example of >> the >> use of this feature is "import java.sql.Date as SqlDate;" >> >> MAJOR ADVANTAGE: This feature would allow easier use of multiple >> classes which have the same name but different packages to be used in >> the same source file. >> >> MAJOR BENEFIT: This will prevent the necessity of fully-qualifiying >> all class references when there is a name collision, leading to more >> readable code. >> >> MAJOR DISADVANTAGE: This will introduce an extra level of >> indirection >> when determing the source of a given class or method, introduce a new >> keyword 'as', and will require changes to IDE code completion >> functionality. >> >> ALTERNATIVES: In some cases, a nested class can be created which >> trivially derives a class involved in the name collision. For a >> method, a wrapper method can be created in the source file. >> >> EXAMPLES >> >> SIMPLE EXAMPLE: >> >> Example #1, duplicate class name >> >> Current code: >> >> new java.sql.Date(new java.util.Date()); >> >> New code: >> >> import java.sql.Date as SqlDate; >> import java.util.Date as UtilDate; >> >> new SqlDate(new UtilDate()); >> >> Example #2, statically imported method alias >> >> Current code: >> >> import static >> com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName; >> >> public static int mrlacsmn(final int arg1, final String arg2){ >> return myReallyLongAndComplicatedStaticMethodName(arg1, arg2); >> } >> >> mrlacsmn(1, a); >> >> New code: >> >> import static >> com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName >> as mrlacsmn; >> >> mrlacsmn(1, a); >> >> ADVANCED EXAMPLE: >> >> Example #3 >> >> Translation of persistent formats between similar APIs. >> >> In many domains, it is not uncommon to have two different APIs with >> classes with the same name. For example, in a production rules API, >> one may have classes "RuleSet" and "Rule". When attempting to use >> the >> API to translate between these these APIs, it must be decided that >> one >> is fully-qualified and one is not. This can lead to code like: >> >> com.example.foo.bar.sdk.RuleSet srcRuleSet = ...; >> com.example.foo.bar.sdk2.RuleSet dstRuleSet = new >> com.example.foo.bar.sdk2.RuleSet(); >> migrate(srcRuleSet, dstRuleSet); >> ... >> >> private static void migrate(com.example.foo.bar.sdk.RuleSet >> srcRuleSet, >> com.example.foo.bar.sdk2.RuleSet dstRuleSet){ >> ... >> } >> >> Note that it is good practice here not to import either class because >> it is too easy to accidentally misuse constants and static methods. >> >> With the 'as' syntax, one could instead write the far less verbose >> and >> more readible: >> >> import com.example.foo.bar.sdk.RuleSet as SrcRuleSet; >> import com.example.foo.bar.sdk2.RuleSet as DstRuleSet; >> >> ... >> >> SrcRuleSet srcRuleSet = ...; >> DstRuleSet destRuleSet = new DstRuleSet(); >> migrate(srcRuleSet, dstRuleSet); >> >> ... >> >> private static void migrate(SrcRuleSet srcRuleSet, >> DstRuleSet dstRuleSet){ >> ... >> } >> >> Example #4 >> >> Ensuring correct method selection when static importing overloaded >> methods. >> >> Current code: >> import static org.testng.Assert.assertEquals; >> >> public static int aeo(Object arg1, Object arg2){ >> assertEquals(arg1, arg2); >> } >> >> public static int aec(Collection arg1, Collection arg2){ >> assertEquals(arg1, arg2); >> } >> >> aeo(obj1, obj2); >> aec(list1, list2); >> >> New code: >> >> import static org.testng.Assert.assertEquals(Object, Object) as aeo; >> import static org.testng.Assert.assertEquals(Collection, >> Collection) as aec; >> >> aeo(obj1, obj2); >> aec(list1, list2); >> >> Note: it is possible that this sort of method selection is beyond the >> scope of a COIN proposal >> >> DETAILS >> >> SPECIFICATION: >> >> Grammar >> >> modification (JLS 3.9): >> Keyword: >> as >> ... >> >> modification (JLS 7.5): >> ImportDeclaration: >> SingleTypeImportDeclarationWithAlias >> SingleStaticImportDeclarationWithAlias >> ... >> >> addition: >> SingleTypeImportDeclarationWithAlias: >> import TypeName as Identifier; >> >> addition: >> SingleStaticImportDeclarationWithAlias: >> import static TypeName . Identifier as Identifier; >> >> >> Note that this would explicitly forbid wildcard imports from being >> aliased. >> >> There are no known effects on the type system or meaning of >> expressions and statements in the Java Programming Language. >> >> COMPILATION: This feature would be a compile-time transform. It >> would >> only affect the way in which a non-fully qualified class or method >> name was resolved to a fully-qualified class or method name. >> >> TESTING: This change would be tested in a manner similar how how the >> existing code which resolves the fully-qualified names of classes and >> methods is tested. >> >> LIBRARY SUPPORT: No change >> >> REFLECTIVE APIS: No change >> >> OTHER CHANGES: No change >> >> MIGRATION: This change is backwards-compatible with existing code. >> >> COMPATIBILITY >> >> BREAKING CHANGES: No change >> >> EXISTING PROGRAMS: No change >> >> REFERENCES >> >> EXISTING BUGS: None at present >> >> URL FOR PROTOTYPE (optional): None at present >> >> > > > From rssh at gradsoft.com.ua Tue Mar 3 02:11:01 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Tue, 3 Mar 2009 12:11:01 +0200 (EET) Subject: PROPOSAL: Multiline strings In-Reply-To: <49ACD1BB.7060505@sun.com> References: <49ACD1BB.7060505@sun.com> Message-ID: > Ruslan, > > This proposal is missing many important details. > .... Thanks, I prepared reviewed proposal >> ALTERNATIVES: understand, thanks for clafifying. > > What are the grammar changes? > Originally idea was: MultilineStringLiteral: """ MultilineStringCharacters/opt """ MultilineStringCharacters: MultilineStringCharacter MultilineStringCharacters MultilineStringCharacter but not " (MultilineStringCharacters but not "") "" MultilineStringCharacter: InputCharacter but not \ EscapeSequence LineTermination But now if we want keep type of LineTermination and unescaped sequence, this will be .. as in next version which I will send by next letter. > Is are three consecutive quote characters escaped in a multi-line string? > \""" will be as (\")""", where \" is EscapeSequence, therefore be escaped. > As has been mentioned in earlier responses, how is whitespace handed? > First idea was does not handle ones at all, now I think that best is adopt proposition by Reinier Zwitserloot (which is the same as in proposal in project koin [http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd] by Jacek Furmankiewicz >> COMPILATION: >> Multiline strings created and used in .class files exactly as ordinary >> strings. >> > > What is the desugaring? > Ok, detailed description is added. Text withing """ brackets processed in next way: 1. splitted to sequence of lines by line termination symbols. 2. escape sequences in each line are processed exactly as in ordinary Java strings. 3. elimination of leading whitespaces are processed in next way: - at first determinated sequence of whitespace symbols (exclude LineTermination, i.e. ST, HP, FF) at first nonempty line in sequence. let's call it 'leading whitespace sequence' - all next lines must start with same leading whitespace sequence, otherwise compile-time error is thrown. - whitespace processing erase such leading sequence from resulting lines 4. set of lines after erasing of leading whitespace sequence is concatenated, with line-termination sequences between two neighbour lines. Inserted linetermination sequence is depend from LineTerminationSuffix, and is - value of systen property 'line.separator' is LineTerminationSuffix is empty - LF (i. e. '\n') when LineTerminationSuffix is 'U' or 'u' - CR LF (i. e. '\r''\n') when LineTerminationSuffix is 'W' or 'w' > Regards, > > -Joe > >> TESTING: >> Nothing special. add multiline strings to test-cases. >> >> LIBRARY SUPPORT: >> None. >> (May be exists sence add simple template processing to standard >> library, but >> I think this is goal of next janguage iteration. Now exists many good >> external >> frameworks, such as velocity: better wait and standartize support of >> winner) >> >> REFLECTIVE APIS: None >> >> OTHER CHANGES: None >> >> MIGRATION: None >> >> COMPABILITY >> None >> >> REFERENCES >> >> http://bugs.sun.com/view_bug.do?bug_id=4165111 >> >> >> >> >> >> >> >> > > From rssh at gradsoft.com.ua Tue Mar 3 02:15:32 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Tue, 3 Mar 2009 12:15:32 +0200 (EET) Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: <49ACCFBD.3010509@sun.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> <49ACCFBD.3010509@sun.com> Message-ID: AUTHOR(s): Ruslan Shevchenko, Jeremy Manson (if agree), Reinier Zwitserloot (if agree) OVERVIEW: FEATURE SUMMARY: new string literals in java language: * multiline string literals. * string literals without escape processing. MAJOR ADVANTAGE: Possibility more elegant to code strings from other languages, such as sql constructions or inline xml (for multiline strings) or regular expressions (for string literals without escape processing). MAJOR DISADVANTAGE I don't know ALTERNATIVES: For multiline strings use operations and concatenation methods, such as: String,contact("Multiline \n", "string "); or String bigString="First line\n"+ "second line" For unescaped ('row') strings - use escaping of ordinary java string. EXAMPLES SIMPLE EXAMPLE: Multiline string:
  StringBuilder sb = new StringBuilder();
  sb.append("""select a from Area a, CountryCodes cc
                where
                   cc.isoCode='UA'
                  and
                   a.owner = cc.country
              """);
  if (question.getAreaName()!=null) {
     sb.append("""and
                  a.name like ?
               """);
     sqlParams.setString(++i,question.getAreaName());
  }
 
instead:
  StringBuilder sb = new StringBuilder();
  sb.append("select a from Area a, CountryCodes cc\n");
  sb.append("where cc.isoCode='UA'\n");
  sb.append("and a.owner=cc.country'\n");
  if (question.getAreaName()!=null) {
     sb.append("and a.name like ?");
     sqlParams.setString(++i,question.getAreaName());
  }
 
Unescaped String:
 String myParrern=''..*\.*'';
 
instead
 String myParrern="\..*\\.*";
 
ADVANCED EXAMPLE: String platformDepended="""q """; is 'q\n' if compiled on Unix and 'q\n\r' if compiled on Windows. String platformIndepended=""" """U; is always '\n'. String platformIndepended=""" """W; is always '\n\r'. String empty=""" """; is empty String foo = """ bar baz bla qux"; is equal to: String foo = "bar\n baz\n bla\nqux"; and the following: String foo = """ foo bar"""; is a compile-time error. String foo= """\"""" is " String foo= """\""" """ is """ DETAILS: Multiline strings are part of program text, which begin and ends by three double quotes. I. e. grammar in 3.10.5 of JLS can be extented as:
MultilineStringLiteral:
        """ MultilineStringCharacters/opt """  LineTerminationSuffix/opt

MultilineStringCharacters:
        MultilineStringCharacter
        MultilineStringCharacters  (MultilineStringCharacter but not ")
        (MultilineStringCharacters but not "") "

MultilineStringCharacter:
        InputCharacter but not \
        EscapeSequence
        LineTermination

LineTerminationSuffix:
                      U | u | W | w

Unescaped strings are part of program text, which begin and ends by two single quotes.
 RowStringLiteral:
                   '' RowInputCharacters/opt '' LineTerminationSuffix/opt

 RowInputCharacters:
                      ' (InputCharacter but not ')
                     |
                      (InputCharacter but not ') '
                     |
                      LineTermination
COMPILATION: Handling of multiline strings: Text withing """ brackets processed in next way: 1. splitted to sequence of lines by line termination symbols. 2. escape sequences in each line are processed exactly as in ordinary Java strings. 3. elimination of leading whitespaces are processed in next way: - at first determinated sequence of whitespace symbols (exclude LineTermination, i.e. ST, HP, FF) at first nonempty line in sequence. let's call it 'leading whitespace sequence' - all next lines must start with same leading whitespace sequence, otherwise compile-time error is thrown. - whitespace processing erase such leading sequence from resulting lines 4. set of lines after erasing of leading whitespace sequence is concatenated, with line-termination sequences between two neighbour lines. Inserted linetermination sequence is depend from LineTerminationSuffix, and is - value of systen property 'line.separator' is LineTerminationSuffix is empty - LF (i. e. '\n') when LineTerminationSuffix is 'U' or 'u' - CR LF (i. e. '\r''\n') when LineTerminationSuffix is 'W' or 'w' Handling of row strings: Text withing '' brackets processed in next way: 1. splitted to sequence of lines by line termination symbols. 2. set of lines after erasing of leading whitespace sequence is concatenated, with line-termination sequences between two neighbour lines, exactly as in case of multiline strings. No escape processing, no leading whitespace elimination are performed for receiving of resulting string value. new strings literals created and used in .class files exactly as ordinary strings. TESTING: Nothing special. add new strings literals to test-cases. LIBRARY SUPPORT: None. (May be exists sense add simple template processing to standard library, but I think this is goal of next language iteration. Now exists many good external frameworks, such as velocity: better wait and standardize support of winner) REFLECTIVE APIS: None OTHER CHANGES: None MIGRATION: None COMPABILITY None REFERENCES http://bugs.sun.com/view_bug.do?bug_id=4165111 http://bugs.sun.com/view_bug.do?bug_id=4472509 http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd by by Jacek Furmankiewicz From reinier at zwitserloot.com Tue Mar 3 02:33:26 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 11:33:26 +0100 Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> <49ACCFBD.3010509@sun.com> Message-ID: <0929E79C-1147-444B-9741-E0833C216D30@zwitserloot.com> I don't think you need the U/W suffix; make all newlines \n regardless of what they are in the source file. If this annoys anybody, they can either manually add the \r in the string, or run a simple .replace("\n", "\r\n") at the end. I find collapsing whitespace far more interesting, but there too a simple method solution works just fine: .replaceAll("\\s+", " ") The problem with the suffixes are the rarity: I doubt anybody would know its even legal in the first place, so anybody that does use it effectively makes his code unreadable until the reader looks up the exotic syntax. Then again, there is precedence; the case of the hexadecimal floating point literal is almost point-for-point the same as this situation: Exotic syntax almost no java programmer even knows is legal ( double foo = 0x1P0D is legal java code!) but exists anyway because literals have a special meaning in java (they get inlined), which stops happening if you use an API utility to do the same thing: Double.longBitsToDouble. Still, in the 0x1P0D case there really is no alternative, whereas here you can always manually add \r to the string. --Reinier Zwitserloot On Mar 3, 2009, at 11:15, rssh at gradsoft.com.ua wrote: > AUTHOR(s): Ruslan Shevchenko, Jeremy Manson (if agree), Reinier > Zwitserloot (if agree) > > OVERVIEW: > > FEATURE SUMMARY: > new string literals in java language: > * multiline string literals. > * string literals without escape processing. > > MAJOR ADVANTAGE: > Possibility more elegant to code strings from other languages, such > as > sql constructions or inline xml (for multiline strings) or regular > expressions > (for string literals without escape processing). > > MAJOR DISADVANTAGE > I don't know > > ALTERNATIVES: > > For multiline strings use operations and concatenation methods, such > as: > > String,contact("Multiline \n", > "string "); > > or > > String bigString="First line\n"+ > "second line" > > For unescaped ('row') strings - use escaping of ordinary java string. > > > EXAMPLES > > SIMPLE EXAMPLE: > > Multiline string: > >
>  StringBuilder sb = new StringBuilder();
>  sb.append("""select a from Area a, CountryCodes cc
>                where
>                   cc.isoCode='UA'
>                  and
>                   a.owner = cc.country
>              """);
>  if (question.getAreaName()!=null) {
>     sb.append("""and
>                  a.name like ?
>               """);
>     sqlParams.setString(++i,question.getAreaName());
>  }
> 
> > instead: >
>  StringBuilder sb = new StringBuilder();
>  sb.append("select a from Area a, CountryCodes cc\n");
>  sb.append("where cc.isoCode='UA'\n");
>  sb.append("and a.owner=cc.country'\n");
>  if (question.getAreaName()!=null) {
>     sb.append("and a.name like ?");
>     sqlParams.setString(++i,question.getAreaName());
>  }
> 
> > Unescaped String: >
> String myParrern=''..*\.*'';
> 
> instead >
> String myParrern="\..*\\.*";
> 
> > ADVANCED EXAMPLE: > > String platformDepended="""q > """; > is 'q\n' if compiled on Unix and 'q\n\r' if compiled on Windows. > > String platformIndepended=""" > """U; > is always '\n'. > > String platformIndepended=""" > """W; > is always '\n\r'. > > String empty=""" > """; > is empty > > String foo = """ > bar > baz > bla > qux"; > > is equal to: String foo = "bar\n baz\n bla\nqux"; > > and the following: > > String foo = """ > foo > bar"""; > > is a compile-time error. > > String foo= """\"""" is " > String foo= """\""" """ is """ > > DETAILS: > > Multiline strings are part of program text, which begin and ends by > three > double quotes. > > I. e. grammar in 3.10.5 of JLS can be extented as: > >
> MultilineStringLiteral:
>        """ MultilineStringCharacters/opt """  LineTerminationSuffix/ 
> opt
>
> MultilineStringCharacters:
>        MultilineStringCharacter
>        MultilineStringCharacters  (MultilineStringCharacter but not ")
>        (MultilineStringCharacters but not "") "
>
> MultilineStringCharacter:
>        InputCharacter but not \
>        EscapeSequence
>        LineTermination
>
> LineTerminationSuffix:
>                      U | u | W | w
>
> 
> > > Unescaped strings are part of program text, which begin and ends by > two > single quotes. > > >
> RowStringLiteral:
>                   '' RowInputCharacters/opt '' LineTerminationSuffix/ 
> opt
>
> RowInputCharacters:
>                      ' (InputCharacter but not ')
>                     |
>                      (InputCharacter but not ') '
>                     |
>                      LineTermination
> 
> > > > COMPILATION: > > Handling of multiline strings: > > Text withing """ brackets processed in next way: > > 1. splitted to sequence of lines by line termination symbols. > 2. escape sequences in each line are processed exactly as in > ordinary Java > strings. > 3. elimination of leading whitespaces are processed in next way: > - at first determinated sequence of whitespace symbols (exclude > LineTermination, i.e. ST, HP, FF) at first nonempty line in sequence. > let's call it 'leading whitespace sequence' > - all next lines must start with same leading whitespace sequence, > otherwise compile-time error is thrown. > - whitespace processing erase such leading sequence from resulting > lines > 4. set of lines after erasing of leading whitespace sequence is > concatenated, with line-termination sequences between two neighbour > lines. > Inserted linetermination sequence is depend from > LineTerminationSuffix, > and is > - value of systen property 'line.separator' is > LineTerminationSuffix > is empty > - LF (i. e. '\n') when LineTerminationSuffix is 'U' or 'u' > - CR LF (i. e. '\r''\n') when LineTerminationSuffix is 'W' or 'w' > > > > Handling of row strings: > Text withing '' brackets processed in next way: > 1. splitted to sequence of lines by line termination symbols. > 2. set of lines after erasing of leading whitespace sequence is > concatenated, with line-termination sequences between two neighbour > lines, > exactly as in case of multiline strings. > > No escape processing, no leading whitespace elimination are > performed for > receiving of resulting string value. > > new strings literals created and used in .class files exactly as > ordinary > strings. > > TESTING: > Nothing special. add new strings literals to test-cases. > > LIBRARY SUPPORT: > None. > > (May be exists sense add simple template processing to standard > library, but > I think this is goal of next language iteration. Now exists many good > external > frameworks, such as velocity: better wait and standardize support of > winner) > > REFLECTIVE APIS: None > > OTHER CHANGES: None > > MIGRATION: None > > COMPABILITY > None > > REFERENCES > > http://bugs.sun.com/view_bug.do?bug_id=4165111 > http://bugs.sun.com/view_bug.do?bug_id=4472509 > http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd by by Jacek > Furmankiewicz > > > > > > > > From rssh at gradsoft.com.ua Tue Mar 3 03:24:57 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Tue, 3 Mar 2009 13:24:57 +0200 (EET) Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: <0929E79C-1147-444B-9741-E0833C216D30@zwitserloot.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> <49ACCFBD.3010509@sun.com> <0929E79C-1147-444B-9741-E0833C216D30@zwitserloot.com> Message-ID: > I don't think you need the U/W suffix; make all newlines \n regardless > of what they are in the source file. If this annoys anybody, they can > either manually add the \r in the string, or run a > simple .replace("\n", "\r\n") at the end. I find collapsing whitespace 1. We must be able easy receive string in 'platform native' encoding. (If i wrote application, which generate part of text file, which I later will open in text editor: this is matter) 2. Hmm, in principle for me difference between suffix and method of string is not big (and smart compiler will be call this methods on constants during compilation) So, in principle suffixes can be changed to 3 methods nativeLf() - replace '\r\n'|'\n' to line terminaton sequence, native for this platform. unixLf() - replace '\r\n' to '\n' windowsLf() - replace '\n' to '\r\n' 3. I does not like names like unixLf() or windowsLf() Are you have any ideas about better names ? From scolebourne at joda.org Tue Mar 3 03:58:16 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 03 Mar 2009 11:58:16 +0000 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> Message-ID: <49AD1B58.5060305@joda.org> Jeremy Manson wrote: >> The principle perceived disadvantage, however, is that it encourages, >> rather than discourages, the use of null values in APIs. > > I would think that the principle disadvantage would be not that it > encourages use of null values (which, as you point out, is fine in > some contexts), but that it encourages programmers not to think about > what happens when there is a null value. But that is exactly what already happens today. Most developers are very poor at thinking through the null consequences of a method - the happy day scenario is the one focussed on. > I can easily imagine > programmers using this all of the time without thinking about it, and > then being surprised when a null ends up in the wrong place and not > knowing how it got there. Even with a simple example: > > public String someFunction(String a, String b) { > String s = a?.concat("foo"); > String t = b?.concat(a); > return myHashMap?.get(t); > } > > Now, someFunction returns null. Is it because a was null? Or b was > null? Or myHashMap was null? Or there was no mapping for t in > myHashMap? Or perhaps it doesn't matter, and thats why the code was written that way. Null as 'don't know' or 'don't care' is incredibly common. > If you want to cut down on > extraneous if-testing, I would use JSR-305's Nullity annotations > instead. What does this code do when passed null? Foo f = new Foo(null); int v = f.value; public class Foo { public final Integer value; public Foo(@Nonnull Integer value) { this.value = value; } } There is a NPE at f.value, not at new Foo(null). You would think that you could never construct an instance of Foo with a val of null, but you can. The @Nonnull annotation doesn't have any real meaning unless it is checked using a tool, and javac isn't such a tool. This will be very confusing when you use Foo from another part of your application and expect the value to be non-null and get a NPE. In fact the @Nonnull is positvely misleading. Basically, you can't rely on JSR-305. The information needs to be rechecked. Thus, whats the point in using it at all?!! Documentation perhaps? Annotations are not suitable for handling language level issues like nulls. Stephen From scolebourne at joda.org Tue Mar 3 04:08:36 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 03 Mar 2009 12:08:36 +0000 Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> <57840985-0B00-417A-ADDD-3B350D674D32@gmx.ch> <1631da7d0903010953s4c35c49akee6177535e13585f@mail.gmail.com> <1051A8B5-30F0-46B7-A23D-D99F6AE3D32D@zwitserloot.com> <49ACCFBD.3010509@sun.com> <0929E79C-1147-444B-9741-E0833C216D30@zwitserloot.com> Message-ID: <49AD1DC4.8040903@joda.org> rssh at gradsoft.com.ua wrote: >> I don't think you need the U/W suffix; make all newlines \n regardless >> of what they are in the source file. If this annoys anybody, they can >> either manually add the \r in the string, or run a >> simple .replace("\n", "\r\n") at the end. I find collapsing whitespace > > > 1. We must be able easy receive string in 'platform native' encoding. > (If i wrote application, which generate part of text file, which I later > will open in text editor: this is matter) > > 2. Hmm, in principle for me difference between suffix and method of string > is not big (and smart compiler will be call this methods on constants > during compilation) > > So, in principle suffixes can be changed to 3 methods > > nativeLf() - replace '\r\n'|'\n' to line terminaton sequence, native > for this platform. > unixLf() - replace '\r\n' to '\n' > windowsLf() - replace '\n' to '\r\n' > > 3. I does not like names like unixLf() or windowsLf() > Are you have any ideas about better names ? I would recommend doing a thorough survey of what other languages do for multi-line strings, including Groovy, Scala, Fan, Python, C# and any others you can think of. Try to find the common design. Stephen From rhvarona at gmail.com Mon Mar 2 23:43:59 2009 From: rhvarona at gmail.com (Roger Hernandez) Date: Tue, 3 Mar 2009 02:43:59 -0500 Subject: Simple Resource Clean-up In-Reply-To: <15e8b9d20903022323k17c3f1afo9919c311070b17be@mail.gmail.com> References: <15e8b9d20903022323k17c3f1afo9919c311070b17be@mail.gmail.com> Message-ID: Sorry I meant to take that part out, since I saw the comments from the previous proposal. The way I envision it working is in a way how C++ template instantiation works. The compiler just requires that a class have an accessible "close()" function, it should not care what interface or class it comes from. That way it can throw any exception type. On Tue, Mar 3, 2009 at 2:23 AM, Neal Gafter wrote: > You say "The object being created must implement the Closeable > interface." But java.sql.Statement, to pick one example, cannot be > made to implement that interface because the exception signatures are > not compatible. > > I'll let others comment about issues with exception handling in the > translation. > > -Neal > > On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez > wrote: > > I saw how the previous Automatic Resource Management proposal got torn to > > pieces but I feel strongly enough about this issue to post a similar > > proposal. > > > > Some points: > > > > I am not a programming language designer. I have very little experience > > with byte code and with design and implementation of compilers. What I > do > > have is many years of experience in writing code for large business > > applications, both in house-custom programs and shrink-wrapped products > sold > > to customers. > > > > About 1/3 of the Java code I write contributes almost nothing to the > > functionality or flexibility of the program. It is composed of very > simple > > and very repetitive resource clean-up code. JDBC code is an especially > bad > > case. I know we should be using JDO or JPA, but: 1) most of the Java > > database code in existence is using JDBC to some extent or another, 2) > for > > the kind of processing our software does with large datasets having > hundreds > > of megabytes of row data and millions of rows per account per month, > custom > > JDBC code still beats the other solutions in memory utilization and > > throughput. > > > > In most business code we don't do complex exception processing. If we > get a > > exception we rollback the transaction and unroll the stack until we reach > > some program level error handler that logs the error for some > administrator > > to review at a later date. So if this proposal is not applicable to > complex > > error handling scenarios, that is fine. Taking care of the simple > scenarios > > will still get rid of most of that 1/3 of the code I write, allowing me > to > > concentrate on the actual program logic, not the resource clean-up noise. > > > > I also program quite a bit in C++ and C# and when I work in Java I sorely > > miss RAII (Resource Acquisition Is Initialization) and the "using" > statement > > respectively. > > > > At the end of the day, what I would like is a solution to minimize all > the > > resource clean-up boiler plate. > > > > > ----------------------------------------------------------------------------------------- > > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > > > > AUTHOR: Roger Hernandez, rogerh at velocityconsultinginc.com > > > > OVERVIEW > > > > FEATURE SUMMARY: Syntactic sugar for simple cases of the common > > new/try/finally/close language idiom. The object being created must > > implement the Closeable interface. > > > > MAJOR ADVANTAGE: Significantly reduces lines of code when working with > > objects that encapsulate external resources that should be closed as soon > as > > possible. Examples are Stream, Reader, Writer classes in java.io, and > > Connection, Statement, PreparedStatement, ResultSet in java.sql.*. > > > > MAJOR BENEFIT: It allows writing code that uses these kinds of object > to > > more clearly express the both the lifetime of the utilization of each > > resource, and allows the logic flow of the code to be more visible. > > > > MAJOR DISADVANTAGE: Either a new keyword, or an additional overloaded > > meaning on an existing keyword. > > > > ALTERNATIVES: You can always use the standard idiom: SomeType val = new > > val(...); try { ... } finally { val.close(); } > > > > EXAMPLES > > > > SIMPLE EXAMPLE: A simple Java version of the command line utility > "tee". > > //This is the existing way of doing it. > > //Lines of code: 19 > > package com.vci.projectcoin.using; > > > > import java.io.*; > > > > public class SimpleExample { > > > > public static void main(String[] args) throws IOException { > > byte []buffer = new byte[1024]; > > FileOutputStream out = new FileOutputStream(args[0]); > > try { > > for (int count; (count = System.in.read(buffer)) != -1;) { > > out.write(buffer, 0, count); > > System.out.write(buffer, 0, count); > > } > > } finally { > > out.close(); > > } > > } > > } > > > > //This is the proposed way of doing it, the compiler converts the > > syntactic sugar into the same byte codes > > //I am adding a new use to the the "try" keyword to avoid adding > more > > to the language, but it would work > > //just a well with a "using" keyword. > > //Lines of code: 16 > > package com.vci.projectcoin.using; > > > > import java.io.*; > > > > public class SimpleExample { > > > > public static void main(String[] args) throws IOException { > > byte []buffer = new byte[1024]; > > try (FileOutputStream out = new FileOutputStream(args[0])) { > > for (int count; (count = System.in.read(buffer)) != -1;) { > > out.write(buffer, 0, count); > > System.out.write(buffer, 0, count); > > } > > } > > } > > } > > > > ADVANCED EXAMPLE: A simple utility to execute a query and write values > as > > a comma delimited file. > > > > //This is the existing way of doing it > > //Lines of code: 55 > > package com.vci.projectcoin.using; > > > > import java.sql.*; > > import java.io.*; > > > > public class AdvancedExample { > > final static String EOL = System.getProperty("line.separator"); > > > > //Command Line: [] > > static public void main(String []args) throws SQLException, > > FileNotFoundException { > > String url = args[0]; > > String sql = args[1]; > > PrintWriter out = new PrintWriter(args.length > 2 ? new > > FileOutputStream(args[2]) : System.out); > > try { > > Connection conn = DriverManager.getConnection(url); > > try { > > Statement query = > > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > > ResultSet.CONCUR_READ_ONLY); > > try { > > ResultSet results = query.executeQuery(sql); > > try { > > ResultSetMetaData meta = results.getMetaData(); > > int colCount = meta.getColumnCount(); > > while (results.next()) { > > for (int index = 1; index <= colCount; index++) > { > > int colType = meta.getColumnType(index); > > boolean quoted = colType == Types.CHAR || > > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || > > colType == Types.NCHAR || > > colType == Types.NVARCHAR || colType == Types.VARCHAR; > > if (quoted) { > > System.out.append('"'); > > } > > System.out.append(results.getString(index)); > > if (quoted) { > > System.out.append('"'); > > } > > if (index < colCount) { > > System.out.print(','); > > } else { > > System.out.print(EOL); > > } > > } > > } > > } finally { > > results.close(); > > } > > } finally { > > query.close(); > > } > > } finally { > > conn.close(); > > } > > } finally { > > out.close(); > > } > > } > > } > > > > //This is the proposed way of doing it > > //This proposal gets rid of the finally clean up per object. It > lets > > one write robust resource clean-up code without a lot of effort. > > //Lines of code: 43 > > package com.vci.projectcoin.using; > > > > import java.sql.*; > > import java.io.*; > > > > public class AdvancedExample { > > final static String EOL = System.getProperty("line.separator"); > > > > //Command Line: [] > > static public void main(String []args) throws SQLException, > > FileNotFoundException { > > String url = args[0]; > > String sql = args[1]; > > try (PrintWriter out = new PrintWriter(args.length > 2 ? new > > FileOutputStream(args[2]) : System.out)) { > > try (Connection conn = DriverManager.getConnection(url)) { > > try (Statement query = > > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > > ResultSet.CONCUR_READ_ONLY)) { > > try (ResultSet results = query.executeQuery(sql)) { > > ResultSetMetaData meta = results.getMetaData(); > > int colCount = meta.getColumnCount(); > > while (results.next()) { > > for (int index = 1; index <= colCount; index++) > { > > int colType = meta.getColumnType(index); > > boolean quoted = colType == Types.CHAR || > > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType > == > > Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; > > if (quoted) { > > System.out.append('"'); > > } > > System.out.append(results.getString(index)); > > if (quoted) { > > System.out.append('"'); > > } > > if (index < colCount) { > > System.out.print(','); > > } else { > > System.out.print(EOL); > > } > > } > > System.out.println(); > > } > > } > > } > > } > > } > > } > > } > > > > //This is an additional syntactic sugar proposal, allowing multiple > > objects to be allocated inside one try block. The compiler converts all > > three programs into the same bytecode > > //This proposal gets rid of the additional indentation level and > > closing brace per object. It further minimize the clean-up boiler-plate, > > allowing the point of the program logic to be clearer. > > //Lines of code: 38 > > package com.vci.projectcoin.using; > > > > import java.sql.*; > > import java.io.*; > > > > public class AdvancedExample { > > final static String EOL = System.getProperty("line.separator"); > > > > //Command Line: [] > > static public void main(String []args) throws SQLException, > > FileNotFoundException { > > String url = args[0]; > > String sql = args[1]; > > try (PrintWriter out = new PrintWriter(args.length > 2 ? new > > FileOutputStream(args[2]) : System.out), > > Statement query = > > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > > ResultSet.CONCUR_READ_ONLY), > > ResultSet results = query.executeQuery(sql)) { > > ResultSetMetaData meta = results.getMetaData(); > > int colCount = meta.getColumnCount(); > > while (results.next()) { > > for (int index = 1; index <= colCount; index++) { > > int colType = meta.getColumnType(index); > > boolean quoted = colType == Types.CHAR || colType == > > Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == > Types.NCHAR > > || colType == Types.NVARCHAR || colType == Types.VARCHAR; > > if (quoted) { > > System.out.append('"'); > > } > > System.out.append(results.getString(index)); > > if (quoted) { > > System.out.append('"'); > > } > > if (index < colCount) { > > System.out.print(','); > > } else { > > System.out.print(EOL); > > } > > } > > System.out.println(); > > } > > } > > } > > } > > > > DETAILS > > The specification requires that the object in the try () block have a > > "close()" method. Wether the method throws any or no exception, or if it > > returns a value or no value does not matter. The proposal is not trying > to > > introduce any new intelligence into the try finally clause, it is just > > syntactic sugar to minimize simple resource clean-up code. > > > > SPECIFICATION: > > The "try" keyword will have an overloaded meaning > > > > CASE 1 > > ------ > > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > > //work gets done here > > } > > > > Will be syntactic sugar for: > > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > > try { > > //work gets done here > > } finally { > > value.close(); > > } > > > > CASE 2 > > ------ > > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > > //work gets done here > > } finally { > > //additional clean-up code > > } > > > > Will be syntactic sugar for: > > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > > try { > > //work gets done here > > } finally { > > value.close(); > > //additional clean-up code > > } > > > > CASE 3 > > ------ > > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) { > > //work gets done here > > } catch (Exception ex) { > > //exception handling code > > } finally { > > //additional clean-up code > > } > > > > Will be syntactic sugar for: > > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > > try { > > //work gets done here > > } catch (Exception ex) { > > //exception handling code > > } finally { > > value.close(); > > //additional clean-up code > > } > > > > CASE 4 > > ------ > > try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) > { > > //work gets done here > > } > > > > Will be syntactic sugar for: > > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > > try { > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > > try { > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > > try { > > //work gets done here > > } finally { > > value3.close(); > > } > > } finally { > > value2.close(); > > } > > } finally { > > value1.close(); > > } > > > > CASE 5 > > ------ > > try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) > { > > //work gets done here > > } finally { > > //additional clean-up code > > } > > > > Will be syntactic sugar for: > > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > > try { > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > > try { > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > > try { > > //work gets done here > > } finally { > > value3.close(); > > } > > } finally { > > value2.close(); > > } > > } finally { > > value1.close(); > > //additional clean-up code > > } > > > > CASE 6 > > ------ > > try (Class1WithCloseMethod value1 = new Class1WithCloseMethod(...), > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...), > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...)) > { > > //work gets done here > > } catch (Exception ex) { > > //exception handling code > > } finally { > > //additional clean-up code > > } > > > > Will be syntactic sugar for: > > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > > try { > > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > > try { > > Class3WithCloseMethod value3 = new Class3WithCloseMethod(...); > > try { > > //work gets done here > > } finally { > > value3.close(); > > } > > } finally { > > value2.close(); > > } > > } catch (Exception ex) { > > //exception handling code > > } finally { > > value1.close(); > > //additional clean-up code > > } > > > > COMPILATION: The SPECIFICATION section above shows the desugaring for > > each case. Byte code would be identical to the desugared constructs. > > > > TESTING: Byte code comparison of common code constructs. If the byte > > code is not identical to the desugared version, test fails. > > > > LIBRARY SUPPORT: No. > > > > REFLECTIVE APIS: No. > > > > OTHER CHANGES: No. > > > > MIGRATION: For each case in the SPECIFICATION section, convert the > > existing code to the syntactic sugar proposal. > > > > > > COMPATIBILITY > > > > BREAKING CHANGES: None. > > > > EXISTING PROGRAMS: Compile accepts both existing and new forms of the > > "try" statement. Byte code does not change. > > > > REFERENCES > > > > EXISTING BUGS: None > > > > > > -- > > Roger Hernandez > > > > > -- Roger Hernandez From rhvarona at gmail.com Tue Mar 3 00:21:19 2009 From: rhvarona at gmail.com (Roger Hernandez) Date: Tue, 3 Mar 2009 03:21:19 -0500 Subject: Simple Resource Clean-up In-Reply-To: <15e8b9d20903022354y62f10866t8f403767d22a874f@mail.gmail.com> References: <15e8b9d20903022323k17c3f1afo9919c311070b17be@mail.gmail.com> <15e8b9d20903022354y62f10866t8f403767d22a874f@mail.gmail.com> Message-ID: The code fragment: class ClassWithClose { public ClassWithClose () { .... } public void close () throws SQLException { if (cond) { throw SQLException("message"); } } } try (ClassWithClose val = new ClassWithClose()) { funcThatThrowsIOException(); } behaves exactly like: ClassWithClose val = new ClassWithClose(); try { funcThatThrowsIOException(); } finally { val.close(); } I am going to see the SQLException being thrown out. On Tue, Mar 3, 2009 at 2:54 AM, Neal Gafter wrote: > Just to make sure I understand, in your specification, if an exception > is thrown from the try block, and then another exception is thrown > from the close() method, the one from the close() is the one that > propogates out? > > On Mon, Mar 2, 2009 at 11:43 PM, Roger Hernandez > wrote: > > Sorry I meant to take that part out, since I saw the comments from the > > previous proposal. The way I envision it working is in a way how C++ > > template instantiation works. The compiler just requires that a class > have > > an accessible "close()" function, it should not care what interface or > class > > it comes from. That way it can throw any exception type. > > - Show quoted text - > > > > On Tue, Mar 3, 2009 at 2:23 AM, Neal Gafter wrote: > >> > >> You say "The object being created must implement the Closeable > >> interface." But java.sql.Statement, to pick one example, cannot be > >> made to implement that interface because the exception signatures are > >> not compatible. > >> > >> I'll let others comment about issues with exception handling in the > >> translation. > >> > >> -Neal > >> > >> On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez > >> wrote: > >> > I saw how the previous Automatic Resource Management proposal got torn > >> > to > >> > pieces but I feel strongly enough about this issue to post a similar > >> > proposal. > >> > > >> > Some points: > >> > > >> > I am not a programming language designer. I have very little > experience > >> > with byte code and with design and implementation of compilers. What > I > >> > do > >> > have is many years of experience in writing code for large business > >> > applications, both in house-custom programs and shrink-wrapped > products > >> > sold > >> > to customers. > >> > > >> > About 1/3 of the Java code I write contributes almost nothing to the > >> > functionality or flexibility of the program. It is composed of very > >> > simple > >> > and very repetitive resource clean-up code. JDBC code is an > especially > >> > bad > >> > case. I know we should be using JDO or JPA, but: 1) most of the Java > >> > database code in existence is using JDBC to some extent or another, 2) > >> > for > >> > the kind of processing our software does with large datasets having > >> > hundreds > >> > of megabytes of row data and millions of rows per account per month, > >> > custom > >> > JDBC code still beats the other solutions in memory utilization and > >> > throughput. > >> > > >> > In most business code we don't do complex exception processing. If we > >> > get a > >> > exception we rollback the transaction and unroll the stack until we > >> > reach > >> > some program level error handler that logs the error for some > >> > administrator > >> > to review at a later date. So if this proposal is not applicable to > >> > complex > >> > error handling scenarios, that is fine. Taking care of the simple > >> > scenarios > >> > will still get rid of most of that 1/3 of the code I write, allowing > me > >> > to > >> > concentrate on the actual program logic, not the resource clean-up > >> > noise. > >> > > >> > I also program quite a bit in C++ and C# and when I work in Java I > >> > sorely > >> > miss RAII (Resource Acquisition Is Initialization) and the "using" > >> > statement > >> > respectively. > >> > > >> > At the end of the day, what I would like is a solution to minimize all > >> > the > >> > resource clean-up boiler plate. > >> > > >> > > >> > > ----------------------------------------------------------------------------------------- > >> > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > >> > > >> > AUTHOR: Roger Hernandez, rogerh at velocityconsultinginc.com > >> > > >> > OVERVIEW > >> > > >> > FEATURE SUMMARY: Syntactic sugar for simple cases of the common > >> > new/try/finally/close language idiom. The object being created must > >> > implement the Closeable interface. > >> > > >> > MAJOR ADVANTAGE: Significantly reduces lines of code when working > with > >> > objects that encapsulate external resources that should be closed as > >> > soon as > >> > possible. Examples are Stream, Reader, Writer classes in java.io, > and > >> > Connection, Statement, PreparedStatement, ResultSet in java.sql.*. > >> > > >> > MAJOR BENEFIT: It allows writing code that uses these kinds of > object > >> > to > >> > more clearly express the both the lifetime of the utilization of each > >> > resource, and allows the logic flow of the code to be more visible. > >> > > >> > MAJOR DISADVANTAGE: Either a new keyword, or an additional > overloaded > >> > meaning on an existing keyword. > >> > > >> > ALTERNATIVES: You can always use the standard idiom: SomeType val = > >> > new > >> > val(...); try { ... } finally { val.close(); } > >> > > >> > EXAMPLES > >> > > >> > SIMPLE EXAMPLE: A simple Java version of the command line utility > >> > "tee". > >> > //This is the existing way of doing it. > >> > //Lines of code: 19 > >> > package com.vci.projectcoin.using; > >> > > >> > import java.io.*; > >> > > >> > public class SimpleExample { > >> > > >> > public static void main(String[] args) throws IOException { > >> > byte []buffer = new byte[1024]; > >> > FileOutputStream out = new FileOutputStream(args[0]); > >> > try { > >> > for (int count; (count = System.in.read(buffer)) != -1;) > { > >> > out.write(buffer, 0, count); > >> > System.out.write(buffer, 0, count); > >> > } > >> > } finally { > >> > out.close(); > >> > } > >> > } > >> > } > >> > > >> > //This is the proposed way of doing it, the compiler converts the > >> > syntactic sugar into the same byte codes > >> > //I am adding a new use to the the "try" keyword to avoid adding > >> > more > >> > to the language, but it would work > >> > //just a well with a "using" keyword. > >> > //Lines of code: 16 > >> > package com.vci.projectcoin.using; > >> > > >> > import java.io.*; > >> > > >> > public class SimpleExample { > >> > > >> > public static void main(String[] args) throws IOException { > >> > byte []buffer = new byte[1024]; > >> > try (FileOutputStream out = new FileOutputStream(args[0])) > { > >> > for (int count; (count = System.in.read(buffer)) != -1;) > { > >> > out.write(buffer, 0, count); > >> > System.out.write(buffer, 0, count); > >> > } > >> > } > >> > } > >> > } > >> > > >> > ADVANCED EXAMPLE: A simple utility to execute a query and write > values > >> > as > >> > a comma delimited file. > >> > > >> > //This is the existing way of doing it > >> > //Lines of code: 55 > >> > package com.vci.projectcoin.using; > >> > > >> > import java.sql.*; > >> > import java.io.*; > >> > > >> > public class AdvancedExample { > >> > final static String EOL = > System.getProperty("line.separator"); > >> > > >> > //Command Line: [] > >> > static public void main(String []args) throws SQLException, > >> > FileNotFoundException { > >> > String url = args[0]; > >> > String sql = args[1]; > >> > PrintWriter out = new PrintWriter(args.length > 2 ? new > >> > FileOutputStream(args[2]) : System.out); > >> > try { > >> > Connection conn = DriverManager.getConnection(url); > >> > try { > >> > Statement query = > >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > >> > ResultSet.CONCUR_READ_ONLY); > >> > try { > >> > ResultSet results = query.executeQuery(sql); > >> > try { > >> > ResultSetMetaData meta = results.getMetaData(); > >> > int colCount = meta.getColumnCount(); > >> > while (results.next()) { > >> > for (int index = 1; index <= colCount; > >> > index++) { > >> > int colType = meta.getColumnType(index); > >> > boolean quoted = colType == Types.CHAR > || > >> > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || > >> > colType == Types.NCHAR > || > >> > colType == Types.NVARCHAR || colType == Types.VARCHAR; > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > > >> > System.out.append(results.getString(index)); > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > if (index < colCount) { > >> > System.out.print(','); > >> > } else { > >> > System.out.print(EOL); > >> > } > >> > } > >> > } > >> > } finally { > >> > results.close(); > >> > } > >> > } finally { > >> > query.close(); > >> > } > >> > } finally { > >> > conn.close(); > >> > } > >> > } finally { > >> > out.close(); > >> > } > >> > } > >> > } > >> > > >> > //This is the proposed way of doing it > >> > //This proposal gets rid of the finally clean up per object. It > >> > lets > >> > one write robust resource clean-up code without a lot of effort. > >> > //Lines of code: 43 > >> > package com.vci.projectcoin.using; > >> > > >> > import java.sql.*; > >> > import java.io.*; > >> > > >> > public class AdvancedExample { > >> > final static String EOL = > System.getProperty("line.separator"); > >> > > >> > //Command Line: [] > >> > static public void main(String []args) throws SQLException, > >> > FileNotFoundException { > >> > String url = args[0]; > >> > String sql = args[1]; > >> > try (PrintWriter out = new PrintWriter(args.length > 2 ? > new > >> > FileOutputStream(args[2]) : System.out)) { > >> > try (Connection conn = DriverManager.getConnection(url)) > { > >> > try (Statement query = > >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > >> > ResultSet.CONCUR_READ_ONLY)) { > >> > try (ResultSet results = query.executeQuery(sql)) > { > >> > ResultSetMetaData meta = results.getMetaData(); > >> > int colCount = meta.getColumnCount(); > >> > while (results.next()) { > >> > for (int index = 1; index <= colCount; > >> > index++) { > >> > int colType = meta.getColumnType(index); > >> > boolean quoted = colType == Types.CHAR || > >> > colType == Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || > colType > >> > == > >> > Types.NCHAR || colType == Types.NVARCHAR || colType == Types.VARCHAR; > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > > >> > System.out.append(results.getString(index)); > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > if (index < colCount) { > >> > System.out.print(','); > >> > } else { > >> > System.out.print(EOL); > >> > } > >> > } > >> > System.out.println(); > >> > } > >> > } > >> > } > >> > } > >> > } > >> > } > >> > } > >> > > >> > //This is an additional syntactic sugar proposal, allowing > multiple > >> > objects to be allocated inside one try block. The compiler converts > all > >> > three programs into the same bytecode > >> > //This proposal gets rid of the additional indentation level and > >> > closing brace per object. It further minimize the clean-up > >> > boiler-plate, > >> > allowing the point of the program logic to be clearer. > >> > //Lines of code: 38 > >> > package com.vci.projectcoin.using; > >> > > >> > import java.sql.*; > >> > import java.io.*; > >> > > >> > public class AdvancedExample { > >> > final static String EOL = > System.getProperty("line.separator"); > >> > > >> > //Command Line: [] > >> > static public void main(String []args) throws SQLException, > >> > FileNotFoundException { > >> > String url = args[0]; > >> > String sql = args[1]; > >> > try (PrintWriter out = new PrintWriter(args.length > 2 ? > new > >> > FileOutputStream(args[2]) : System.out), > >> > Statement query = > >> > conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, > >> > ResultSet.CONCUR_READ_ONLY), > >> > ResultSet results = query.executeQuery(sql)) { > >> > ResultSetMetaData meta = results.getMetaData(); > >> > int colCount = meta.getColumnCount(); > >> > while (results.next()) { > >> > for (int index = 1; index <= colCount; index++) { > >> > int colType = meta.getColumnType(index); > >> > boolean quoted = colType == Types.CHAR || colType == > >> > Types.LONGNVARCHAR || colType == Types.LONGVARCHAR || colType == > >> > Types.NCHAR > >> > || colType == Types.NVARCHAR || colType == Types.VARCHAR; > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > System.out.append(results.getString(index)); > >> > if (quoted) { > >> > System.out.append('"'); > >> > } > >> > if (index < colCount) { > >> > System.out.print(','); > >> > } else { > >> > System.out.print(EOL); > >> > } > >> > } > >> > System.out.println(); > >> > } > >> > } > >> > } > >> > } > >> > > >> > DETAILS > >> > The specification requires that the object in the try () block have > a > >> > "close()" method. Wether the method throws any or no exception, or if > >> > it > >> > returns a value or no value does not matter. The proposal is not > trying > >> > to > >> > introduce any new intelligence into the try finally clause, it is just > >> > syntactic sugar to minimize simple resource clean-up code. > >> > > >> > SPECIFICATION: > >> > The "try" keyword will have an overloaded meaning > >> > > >> > CASE 1 > >> > ------ > >> > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) > { > >> > //work gets done here > >> > } > >> > > >> > Will be syntactic sugar for: > >> > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } finally { > >> > value.close(); > >> > } > >> > > >> > CASE 2 > >> > ------ > >> > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) > { > >> > //work gets done here > >> > } finally { > >> > //additional clean-up code > >> > } > >> > > >> > Will be syntactic sugar for: > >> > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } finally { > >> > value.close(); > >> > //additional clean-up code > >> > } > >> > > >> > CASE 3 > >> > ------ > >> > try (ClassWithCloseMethod value = new ClassWithCloseMethod(...)) > { > >> > //work gets done here > >> > } catch (Exception ex) { > >> > //exception handling code > >> > } finally { > >> > //additional clean-up code > >> > } > >> > > >> > Will be syntactic sugar for: > >> > ClassWithCloseMethod value = new ClassWithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } catch (Exception ex) { > >> > //exception handling code > >> > } finally { > >> > value.close(); > >> > //additional clean-up code > >> > } > >> > > >> > CASE 4 > >> > ------ > >> > try (Class1WithCloseMethod value1 = new > Class1WithCloseMethod(...), > >> > Class2WithCloseMethod value2 = new > Class2WithCloseMethod(...), > >> > Class3WithCloseMethod value3 = new > Class3WithCloseMethod(...)) > >> > { > >> > //work gets done here > >> > } > >> > > >> > Will be syntactic sugar for: > >> > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > >> > try { > >> > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > >> > try { > >> > Class3WithCloseMethod value3 = new > >> > Class3WithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } finally { > >> > value3.close(); > >> > } > >> > } finally { > >> > value2.close(); > >> > } > >> > } finally { > >> > value1.close(); > >> > } > >> > > >> > CASE 5 > >> > ------ > >> > try (Class1WithCloseMethod value1 = new > Class1WithCloseMethod(...), > >> > Class2WithCloseMethod value2 = new > Class2WithCloseMethod(...), > >> > Class3WithCloseMethod value3 = new > Class3WithCloseMethod(...)) > >> > { > >> > //work gets done here > >> > } finally { > >> > //additional clean-up code > >> > } > >> > > >> > Will be syntactic sugar for: > >> > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > >> > try { > >> > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > >> > try { > >> > Class3WithCloseMethod value3 = new > >> > Class3WithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } finally { > >> > value3.close(); > >> > } > >> > } finally { > >> > value2.close(); > >> > } > >> > } finally { > >> > value1.close(); > >> > //additional clean-up code > >> > } > >> > > >> > CASE 6 > >> > ------ > >> > try (Class1WithCloseMethod value1 = new > Class1WithCloseMethod(...), > >> > Class2WithCloseMethod value2 = new > Class2WithCloseMethod(...), > >> > Class3WithCloseMethod value3 = new > Class3WithCloseMethod(...)) > >> > { > >> > //work gets done here > >> > } catch (Exception ex) { > >> > //exception handling code > >> > } finally { > >> > //additional clean-up code > >> > } > >> > > >> > Will be syntactic sugar for: > >> > Class1WithCloseMethod value1 = new Class1WithCloseMethod(...); > >> > try { > >> > Class2WithCloseMethod value2 = new Class2WithCloseMethod(...); > >> > try { > >> > Class3WithCloseMethod value3 = new > >> > Class3WithCloseMethod(...); > >> > try { > >> > //work gets done here > >> > } finally { > >> > value3.close(); > >> > } > >> > } finally { > >> > value2.close(); > >> > } > >> > } catch (Exception ex) { > >> > //exception handling code > >> > } finally { > >> > value1.close(); > >> > //additional clean-up code > >> > } > >> > > >> > COMPILATION: The SPECIFICATION section above shows the desugaring > for > >> > each case. Byte code would be identical to the desugared constructs. > >> > > >> > TESTING: Byte code comparison of common code constructs. If the > byte > >> > code is not identical to the desugared version, test fails. > >> > > >> > LIBRARY SUPPORT: No. > >> > > >> > REFLECTIVE APIS: No. > >> > > >> > OTHER CHANGES: No. > >> > > >> > MIGRATION: For each case in the SPECIFICATION section, convert the > >> > existing code to the syntactic sugar proposal. > >> > > >> > > >> > COMPATIBILITY > >> > > >> > BREAKING CHANGES: None. > >> > > >> > EXISTING PROGRAMS: Compile accepts both existing and new forms of > the > >> > "try" statement. Byte code does not change. > >> > > >> > REFERENCES > >> > > >> > EXISTING BUGS: None > >> > > >> > > >> > -- > >> > Roger Hernandez > >> > > >> > > > > > > > > > -- > > Roger Hernandez > > > -- Roger Hernandez From rhvarona at gmail.com Tue Mar 3 00:34:11 2009 From: rhvarona at gmail.com (Roger Hernandez) Date: Tue, 3 Mar 2009 03:34:11 -0500 Subject: Simple Resource Clean-up In-Reply-To: <17b2302a0903030018p3736108eq9e3baf3ce5ab4b5b@mail.gmail.com> References: <17b2302a0903030018p3736108eq9e3baf3ce5ab4b5b@mail.gmail.com> Message-ID: On Tue, Mar 3, 2009 at 3:18 AM, Joshua Bloch wrote: > Roger, > > On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez wrote: > >> I saw how the previous Automatic Resource Management proposal got torn to >> pieces > > > That's not quite fair. Only one person objected, and I had good responses > to all of his objections. So I believe the proposal is alive and well. > Others have informed me (off list) that they see Automatic Resource > Management as perhaps the most valuable language change that we could > introduce for Java 7. > > Regards, > > Josh > > You are right, I used strong wording but my concern was that the proposal would not be followed up on, and we would have to live with another 4 years of this before JDK 1.8 came out. I think that your proposal, Automatic Resource Management is definitely more thought out and more complete than what I proposed, and handles more complex scenarios and corner cases. It would be a very valuable feature if it gets into JDK 1.7. However, I am worried that the extra complexity will cause it to be dropped altogether, so if something gets implemented that takes care of the simpler scenarios that make up 80% of the cases, that would be good enough from my point of view. Thanks, -- Roger Hernandez From R.Spilker at topdesk.com Tue Mar 3 05:01:10 2009 From: R.Spilker at topdesk.com (=?us-ascii?Q?Roel_Spilker?=) Date: Tue, 3 Mar 2009 14:01:10 +0100 Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: <0929E79C-1147-444B-9741-E0833C216D30@zwitserloot.com> References: Message-ID: > String foo= """\""" """ is """ Is there really a need for escaping? If users want to escape, they can still use the regular "" string literals. I'd rather have no escaping at all. Otherwise, you probably also need to escape the \ if you want the string to contain \" at the end. """An example:\\"""". The rule 'The new string literals don't support any escape sequences' if much better than 'The new string literals only support the escape sequences \""", which means """ and \\, which means \\'. Mind though, that \Uxxxx will always an escape sequence, since it is processed while before the source is sent to the tokenizer. What about supporting " or "" at the beginning or end of the new string literals? That would result in """" or """"". Or even """""""" if you push it to the limits. Wouldn't that be hard on the compiler? Roel -----Oorspronkelijk bericht----- Van: reinier at zwitserloot.com [mailto:coin-dev-bounces at openjdk.java.net] Namens Reinier Zwitserloot Verzonden: dinsdag 3 maart 2009 11:33 Aan: coin-dev at openjdk.java.net Onderwerp: Re: PROPOSAL: String literals: version 1.1 I don't think you need the U/W suffix; make all newlines \n regardless of what they are in the source file. If this annoys anybody, they can either manually add the \r in the string, or run a simple .replace("\n", "\r\n") at the end. I find collapsing whitespace far more interesting, but there too a simple method solution works just fine: .replaceAll("\\s+", " ") The problem with the suffixes are the rarity: I doubt anybody would know its even legal in the first place, so anybody that does use it effectively makes his code unreadable until the reader looks up the exotic syntax. Then again, there is precedence; the case of the hexadecimal floating point literal is almost point-for-point the same as this situation: Exotic syntax almost no java programmer even knows is legal ( double foo = 0x1P0D is legal java code!) but exists anyway because literals have a special meaning in java (they get inlined), which stops happening if you use an API utility to do the same thing: Double.longBitsToDouble. Still, in the 0x1P0D case there really is no alternative, whereas here you can always manually add \r to the string. --Reinier Zwitserloot On Mar 3, 2009, at 11:15, rssh at gradsoft.com.ua wrote: > AUTHOR(s): Ruslan Shevchenko, Jeremy Manson (if agree), Reinier > Zwitserloot (if agree) > > OVERVIEW: > > FEATURE SUMMARY: > new string literals in java language: > * multiline string literals. > * string literals without escape processing. > > MAJOR ADVANTAGE: > Possibility more elegant to code strings from other languages, such > as sql constructions or inline xml (for multiline strings) or regular > expressions (for string literals without escape processing). > > MAJOR DISADVANTAGE > I don't know > > ALTERNATIVES: > > For multiline strings use operations and concatenation methods, such > as: > > String,contact("Multiline \n", > "string "); > > or > > String bigString="First line\n"+ > "second line" > > For unescaped ('row') strings - use escaping of ordinary java string. > > > EXAMPLES > > SIMPLE EXAMPLE: > > Multiline string: > >
>  StringBuilder sb = new StringBuilder();  sb.append("""select a from 
> Area a, CountryCodes cc
>                where
>                   cc.isoCode='UA'
>                  and
>                   a.owner = cc.country
>              """);
>  if (question.getAreaName()!=null) {
>     sb.append("""and
>                  a.name like ?
>               """);
>     sqlParams.setString(++i,question.getAreaName());
>  }
> 
> > instead: >
>  StringBuilder sb = new StringBuilder();  sb.append("select a from 
> Area a, CountryCodes cc\n");  sb.append("where cc.isoCode='UA'\n");  
> sb.append("and a.owner=cc.country'\n");  if 
> (question.getAreaName()!=null) {
>     sb.append("and a.name like ?");
>     sqlParams.setString(++i,question.getAreaName());
>  }
> 
> > Unescaped String: >
> String myParrern=''..*\.*'';
> 
> instead >
> String myParrern="\..*\\.*";
> 
> > ADVANCED EXAMPLE: > > String platformDepended="""q > """; > is 'q\n' if compiled on Unix and 'q\n\r' if compiled on Windows. > > String platformIndepended=""" > """U; > is always '\n'. > > String platformIndepended=""" > """W; > is always '\n\r'. > > String empty=""" > """; > is empty > > String foo = """ > bar > baz > bla > qux"; > > is equal to: String foo = "bar\n baz\n bla\nqux"; > > and the following: > > String foo = """ > foo > bar"""; > > is a compile-time error. > > String foo= """\"""" is " > String foo= """\""" """ is """ > > DETAILS: > > Multiline strings are part of program text, which begin and ends by > three double quotes. > > I. e. grammar in 3.10.5 of JLS can be extented as: > >
> MultilineStringLiteral:
>        """ MultilineStringCharacters/opt """  LineTerminationSuffix/ 
> opt
>
> MultilineStringCharacters:
>        MultilineStringCharacter
>        MultilineStringCharacters  (MultilineStringCharacter but not ")
>        (MultilineStringCharacters but not "") "
>
> MultilineStringCharacter:
>        InputCharacter but not \
>        EscapeSequence
>        LineTermination
>
> LineTerminationSuffix:
>                      U | u | W | w
>
> 
> > > Unescaped strings are part of program text, which begin and ends by > two single quotes. > > >
> RowStringLiteral:
>                   '' RowInputCharacters/opt '' LineTerminationSuffix/ 
> opt
>
> RowInputCharacters:
>                      ' (InputCharacter but not ')
>                     |
>                      (InputCharacter but not ') '
>                     |
>                      LineTermination
> 
> > > > COMPILATION: > > Handling of multiline strings: > > Text withing """ brackets processed in next way: > > 1. splitted to sequence of lines by line termination symbols. > 2. escape sequences in each line are processed exactly as in ordinary > Java strings. > 3. elimination of leading whitespaces are processed in next way: > - at first determinated sequence of whitespace symbols (exclude > LineTermination, i.e. ST, HP, FF) at first nonempty line in sequence. > let's call it 'leading whitespace sequence' > - all next lines must start with same leading whitespace sequence, > otherwise compile-time error is thrown. > - whitespace processing erase such leading sequence from resulting > lines 4. set of lines after erasing of leading whitespace sequence is > concatenated, with line-termination sequences between two neighbour > lines. > Inserted linetermination sequence is depend from > LineTerminationSuffix, and is > - value of systen property 'line.separator' is > LineTerminationSuffix is empty > - LF (i. e. '\n') when LineTerminationSuffix is 'U' or 'u' > - CR LF (i. e. '\r''\n') when LineTerminationSuffix is 'W' or 'w' > > > > Handling of row strings: > Text withing '' brackets processed in next way: > 1. splitted to sequence of lines by line termination symbols. > 2. set of lines after erasing of leading whitespace sequence is > concatenated, with line-termination sequences between two neighbour > lines, exactly as in case of multiline strings. > > No escape processing, no leading whitespace elimination are performed > for receiving of resulting string value. > > new strings literals created and used in .class files exactly as > ordinary strings. > > TESTING: > Nothing special. add new strings literals to test-cases. > > LIBRARY SUPPORT: > None. > > (May be exists sense add simple template processing to standard > library, but I think this is goal of next language iteration. Now > exists many good external frameworks, such as velocity: better wait > and standardize support of > winner) > > REFLECTIVE APIS: None > > OTHER CHANGES: None > > MIGRATION: None > > COMPABILITY > None > > REFERENCES > > http://bugs.sun.com/view_bug.do?bug_id=4165111 > http://bugs.sun.com/view_bug.do?bug_id=4472509 > http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd by by Jacek > Furmankiewicz > > > > > > > > From neal at gafter.com Tue Mar 3 06:58:36 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 06:58:36 -0800 Subject: Simple Resource Clean-up In-Reply-To: References: <17b2302a0903030018p3736108eq9e3baf3ce5ab4b5b@mail.gmail.com> Message-ID: <15e8b9d20903030658s427e7f7ge52e6f0503ed196b@mail.gmail.com> The problem with addressing this sort of problem as a language change rather than an API is that the solution has to attempt to be a one-size-fits-all: you have to decide which 80% to aim for. An API - or a set of APIs - can instead be tuned to the use cases. On Tue, Mar 3, 2009 at 12:34 AM, Roger Hernandez wrote: > On Tue, Mar 3, 2009 at 3:18 AM, Joshua Bloch wrote: > >> Roger, >> >> On Mon, Mar 2, 2009 at 9:02 PM, Roger Hernandez wrote: >> >>> I saw how the previous Automatic Resource Management proposal got torn to >>> pieces >> >> >> That's not quite fair. ?Only one person objected, and I had good responses >> to all of his objections. ?So I believe the proposal is alive and well. >> ?Others have informed me (off list) that they see Automatic Resource >> Management as perhaps the most valuable language change that we could >> introduce for Java 7. >> >> ? ? ? Regards, >> >> ? ? ? Josh >> >> > > > You are right, I used strong wording but my concern was that the proposal > would not be followed up on, and we would have to live with another 4 years > of this before JDK 1.8 came out. > > I think that your proposal, Automatic Resource Management is definitely more > thought out and more complete than what I proposed, and handles more complex > scenarios and corner cases. ? It would be a very valuable feature if it gets > into JDK 1.7. ?However, I am worried that the extra complexity will cause it > to be dropped altogether, so if something gets implemented that takes care > of the simpler scenarios that make up 80% of the cases, that would be good > enough from my point of view. > > Thanks, > > -- > Roger Hernandez > > From david.goodenough at linkchoose.co.uk Tue Mar 3 06:59:02 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Tue, 3 Mar 2009 14:59:02 +0000 Subject: PROPOSAL: Lightweight Properties Message-ID: <200903031459.03331.david.goodenough@linkchoose.co.uk> Below is my proposal for Lightweight Properties. I know that the syntax change is an abbomination to some people, but I have tried to reduce this to its absolute minimum, while still getting a significant benefit. PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR(S): David Goodenough, long time Java user. I can be reached at david.goodenough at linkchoose.co.uk. OVERVIEW FEATURE SUMMARY: Lightweight Property support MAJOR ADVANTAGE: Both BeansBinding (whether JSR-295 or others such an JFace or the JGoodies binding) and the JPA Criteria API currently require field names (as Strings) as arguments, which an IDE/compiler can not check. With this proposal the strings would be abandoned, and the IDE/compiler will be able to check the correctness of the code. MAJOR BENEFIT: Manual checking no longer required. This proposal introduces a simple well defined IDE/compiler checkable solution. MAJOR DISADVANTAGE: It is a language change, and this seems to upset some people. ALTERNATIVES: None really, apart from using another language or continuing to use String names. The existing solutions all require String names which are uncheckable. EXAMPLES Lets assume we have a POJO called foo, of type Foo with a field bar of type Bar, which itself has a field of type Jim called jim. There are two forms of lightweight properties:- 1) foo#bar would be translated by the compiler into:- new Property(foo,"bar"); while foo#bar#jim would be translated into:- new Property(foo,"bar","jim"); 2) Foo#bar would be translated into:- new Property(Foo.class,"bar"); while Foo#bar#jim would be translated into:- new Property(Foo.class,"bar","jim"); These two forms create (1) a bound Property, or (2) an unbound one. Bound Properties are explicitly bound to a particular instance of a class (in this case foo), while unbound Properties are templates which can be applied to any instance of class Foo. Actually bound properties can also be used as unbound properties, but that is a harmless and useful side effect not a primary intent. The Property class would need to be added (it is appended below), and should be added either to the java.beans package or to the java.lang.reflect package (with which is probably has more in common). Syntactically a "#" can be placed wherever a "." can be placed (except inside a number), and the same checks need to be made (that each field to the right of a # is a field in the left hand side) as would be made for a ".". The only difference is in field visibility - For the "#" any field is visible, which follows the model currently available in the Field class with getDeclaredFields(). It also follows the model that while a field might be private and therefore not directly accessible from outside, getters and setters can provide access. The Property object provides type safe access to the field in the form of getters and setters. These come in pairs, one for bound and the other for unbound access. So for bound access no object is required to fetch the value, for an unbound object the parent object needs to be specified. So if we have:- Propertyprop = foo#bar; we can later say:- Bar b = prop.get(); or for an unbound one from a second Foo object foo2:- Bar b = prop.get(foo2); The getters and setters in the Property object will defer to explicitly coded getters and setters if present, otherwise they will use the Field getter and setter. If a setter is not explicitly coded, the implicit setter will look for a PropertyChangeSupport object in the parent object of the rightmost field and fire a PropertyChangeEvent to that object. There are also two Annotations provided by the Property class, ReadOnly and WriteOnly. These stop implicit getters and setters from trying to read/write the property. Talking of Annotations, this notation can also be used to get at the Annotations for a field. So to test for the presence of an Annotation Ann on Foo.bar we would use:- if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... SIMPLE EXAMPLE: To take an example from BeansBinding (taken from Shannon Hickey's blog):- // create a BeanProperty representing a bean's firstName Property firstP = BeanProperty.create("firstName"); // Bind Duke's first name to the text property of a Swing JTextField BeanProperty textP = BeanProperty.create("text"); Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, firstP, textfield, textP); binding.bind(); would instead be written:- Binding binding = Bindings.createAutoBinding(READ_WRITE, duke#firstName, textfield#text); binding.bind(); which of course can be checked by the IDE/compiler, and will not wait until run time (not even instantiation time) to show up the error. ADVANCED EXAMPLE: For a JComboBox (or JList or JTable or JTree) there is a need to map a list of objects to the value strings (or column contents). For this we need to have an unbound Property which can be applied to each element of the list. Duke duke; Listdukes; BoundComboBox combo = new BoundComboBox(dukes,Duke#fullname,this#duke); and now the combo box will be populated from the list dukes, and the display values in the list will be taken from the fullname field of each Duke element, and the initial value will be set from the local class field duke and any changes to the combo box selected element will be reflected back to the duke field. DETAILS SPECIFICATION: This proposal adds a new syntactic element, "#", which can be used in the same way that "." can be used to qualify fields within a Java object. COMPILATION: This proposal requires no change to the class files, and is implemented by a simple generation of the required instance using the relevant Property constructor. Obviously the compiler would have to make sure that the use that the property object was being put to (in the examples above the left hand side of the assignment) had the correct Generic attributes. TESTING: How can the feature be tested? LIBRARY SUPPORT: The new Property class is required (see below). REFLECTIVE APIS: No changes are required to the reflective APIs although it makes extensive use of those APIs. OTHER CHANGES: No other changes are requires. MIGRATION: Fortunately there is no code that is formally part of J2SE 6 which uses such Properties. There are however two proposals which will need it (BeansBinding and JPA Criteria API), but neither of these seem to be destined to be part of J2SE 7 (BeansBinding seems to have died the death and the Criteria API would be part of the next J2EE which will follow J2SE 7), so this will provide a base for them to use and no existing code need to be updated. There are other extant Beans-Binding libraries, which could be modified to use this proposal, but as none of the existing features have been changed there is no need to change them (other than for type safety and compiler/IDE checkability). COMPATIBILITY BREAKING CHANGES: None. This change should not make any existing correct code fail to compile or run or change the way in which it compiles/runs. EXISTING PROGRAMS: No change required to any existing programs REFERENCES EXISTING BUGS: None URL FOR PROTOTYPE (optional): I do not have the knowledge to make changes to the compiler, and the only documentation making such changes concentrated on adding operators not changes at this level. So there is no prototype of the compiler part, but the Property class follows:- package java.lang.reflect; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyChangeSupport; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Property class * This is the support class for use with the # notation to provide lightweight * Property support for Java. * * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd * @licence LPGL V2 : details of which can be found at http://fsf.org. * @author david.goodenough at linkchoose.co.uk * * @param The Parent class for this field * @param The Type of this field */ public class Property { ????private C parent; ???private Class parentClass; private Field[] fields; private PropertyDescriptor[] pd = null; /** * Constructor used to create Property objects. The Parent object may be * null, but should normally be specified as it can be overridden anyway. * @param parent C object that contains the field * @param field Field describing this field */ public Property(C parent, String ... fieldNames) { ???????this.parent = parent; ????????this(parent.getClass(), fieldNames); ????????} ????/** ?????* Constructor for unbound Properties, but also used internally after setting ?????* the parent object by the bound Property objects. ?????* @param parentClass Class of the parent object ?????* @param fieldNames String[] of field names ?????*/ ????public Property(ClassparentClass, String .. fieldNames) { ????????this.parentClass = parentClass; fields = new Field[fieldNames.length]; pd = new PropertyDescriptor[fieldNames.length]; outer: for(int index = 0; index < fields.length; index++) { Field[]dclFields = parentClass.getDeclaredFields(); ????for(Field field:dclFields) { if(field.getName().equals(fieldNames[index])) { fields[index] = field; field.setAccessible(true); try { BeanInfo beanInfo = Introspector.getBeanInfo(parent.getClass()); PropertyDescriptor[]props = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor prop : props) { if(prop.getName().equals(field.getName())) { pd[index] = prop; break; } } } catch(Exception e) { /* assume can not find getter/setter */ } parentClass = field.getType(); continue outer; } } throw new IllegalArgumentException("Field " + fieldNames[index] + " not found in class " + parentClass.getCanonicalName()); } } /** * Getter from the field in the parent specified when this Property was created. * @see Property.get(C otherParent) * @return F the value of this field */ public F get() { return get(parent); } /** * Getter with explicit parent. * This code will check see if this field is WriteOnly, and complain if it is. * It will then see if the use has provided am explicit getter, and call that * if present, otherwise it will just fetch the value through the Field provided * method. * @param otherParent C parent object * @return F value of the field */ @SuppressWarnings("unchecked") // This should actually not be needed, // but the Field.get method is not typed public F get(C otherParent) { Object result = otherParent; try { for(int index = 0; index < fields.length; index++) { if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) throw new IllegalAccessException( "Can not get from a WriteOnly field - " + fields[index].getName()); Method getter = pd[index] == null ? null : pd[index].getReadMethod(); if(getter == null) result = fields[index].get(result); else result = getter.invoke(result); } } catch(Exception e) { throw new RuntimeException("Should not occur exception", e); } return (F)result; } /** * Setter to set the value of the field in the parent object declared with the * Property object * @param newValue F new value of this field */ public void set(F newValue) { set(parent,newValue); } /** * Setter to set the value of the field to an explicit parent object. * If there is a ReadOnly annotation, then we object. If there is an explicit * setter then we use that, otherwise we set the field using the Field provided * set method and if there is a PropertyChangeSupport field, fire a property * change event to it. * We walk our way down the field chain, until we have the last object and its * field, and then we do the set. * @param parent C explicit parent object * @param newValue F new value for field in parent */ public void set(C parent,F newValue) { try { Object last = parent; int index; for(index = 0; index < fields.length - 1; index++) { if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) throw new IllegalAccessException( "Can not get from a WriteOnly field - " + fields[index].getName()); Method getter = pd[index] == null ? null : pd[index].getReadMethod(); if(getter == null) last = fields[index].get(last); else last = getter.invoke(last); } if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) throw new IllegalAccessException( "Can not get from a WriteOnly field - " + fields[index].getName()); Method setter = pd[index] == null ? null : pd[index].getWriteMethod(); if(setter == null) { PropertyChangeSupport pcs = findPcs(last.getClass()); fields[index].set(last,newValue); if(pcs != null) pcs.firePropertyChange(fields[index].getName(), newValue, fields[index].get(last)); } else setter.invoke(last,newValue); } catch(Exception e) { throw new RuntimeException("Should not occur exception", e); } } /** * This is used so that the caller can view the Field name * @return String field name */ public String[] getFieldName() { String[]names = new String[fields.length]; for(int index = 0; index < fields.length; index++) { names[index] = fields[index].getName(); } return names; } ????/** ?????* This method is used to fetch the Field array, which is useful if you need to ?????* access the Annotations of a field. ?????* @return Field[] the array of Fields describing this Property. ?????*/ ????public Field[] getFields() { ????????return fields; ????????} /** * This private method looks for a PropertyChangeSupport object in the class and * if one is found it will return it. It looks right the way up the class tree * by recurring up the superClasses. * @param parent Class to check for PropertyChangeSupport fields * @return PropertyChangeSupport first found object, or null if not found */ private PropertyChangeSupport findPcs(Class parent) { Field fields[] = parent.getDeclaredFields(); for(Field field:fields) { field.setAccessible(true); try { if(field.getType() == PropertyChangeSupport.class) return (PropertyChangeSupport)field.get(parent); } catch(Exception e) { } } // If we did not find it then try the superclass ClasssuperClass = parent.getSuperclass(); if(superClass == null) return null; return findPcs(parent.getClass().getSuperclass()); } /** * This annotation is used to mark a field as WriteOnly, i.e. it can not be read. * This stops the automatic getter operation. */ public @interface WriteOnly { } /** * This annotation is used to mark a field as ReadOnly, i.e. it can not be written. * This stops the automatic setter operation. */ public @interface ReadOnly { } } From neal at gafter.com Tue Mar 3 07:04:04 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 07:04:04 -0800 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <08E77F6F-6D7F-4A0F-B389-4851039220F0@zwitserloot.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> <49ACCE49.8030103@sun.com> <15e8b9d20903022333x33e5fbe2kd69df4ca94543da2@mail.gmail.com> <08E77F6F-6D7F-4A0F-B389-4851039220F0@zwitserloot.com> Message-ID: <15e8b9d20903030704j4fbf2f31if64f59b381c8864f@mail.gmail.com> I think relaxing the rules for interoperability is a great idea. I know a few places where Java's language rules interfere with interoperability, but I wasn't aware of this one before. I suggest you write it as a separate proposal, please. On Tue, Mar 3, 2009 at 2:06 AM, Reinier Zwitserloot wrote: > Maybe I'm making this too simple, but what if javac will treat all > catch blocks of a type that isn't thrown by the try block as warnings > instead of errors? That fixes Neal's Improved Exception Handling issue > of not being 100% source compatible with java 6, no? > > I assume source compatibility where code that is clearly broken > results in a warning in java 7 (but is still compiled with exactly the > same semantics) whereas it was silently compiled by java 6 is only > good news. > > Also, because in just about every other language on the JVM, checked > exceptions can be thrown without being declared, I think this is a > good idea in general, considering that java wants to be more > interoperable with non-java JVM languages. To work around this issue > now, you have to either wrap the call in a wrapper method that adds > the exception to the throws list, or you have to create a dummy method > that declares the throwable in the throws list but doesn't throw it, > just so javac will stop refusing to compile your code. That's clearly > a hack solution, and the elimination of it should be a good thing, > even if you need to use a @SuppressWarnings instead, no? > > Should I write up a proposal for this? Should Neal add it to his > proposal? Or is it just a horribly stupid idea? :) > > ?--Reinier Zwitserloot > > > > On Mar 3, 2009, at 08:33, Neal Gafter wrote: > >> On Mon, Mar 2, 2009 at 10:29 PM, Joseph D. Darcy >> wrote: >>>> MAJOR DISADVANTAGE: >>>> >>>> One-time implementation cost for adding the features to the >>>> compiler. >>>> Longer language specification in describing the behavior. >>>> >>> >>> What sort of poor programming practices could this feature >>> encourage or >>> enable? >> >> I don't see any, but perhaps I'm shortsighted. >> >>>> The type system is affected as follows: For the purpose of type >>>> checking, a catch parameter declared with a disjunction has type >>>> lub(t1, t2, ...) [JLS3 15.12.2.5]. >>> >>> In terms of finding the members of the type, it is good existing >>> concepts in >>> the JLS can be used. >>> >>> What happens if someone writes >>> >>> ? catch(final IOException | SomeSubclassOfIOException e) {...} >>> >>> In other words, is it legal to have subclasses of a caught >>> exception listed >>> too? >> >> I don't really care one way or the other. ?As written, yes, it is >> allowed and means the same thing as the supertype alone. >> >>>> To avoid the need to add support for general disjunctive types, but >>>> leaving open the possibility of a future extension along these >>>> lines, >>>> a catch parameter whose type has more than one disjunct is >>>> required to >>>> be declared final. >>>> >>> >>> I think that is a fine compromise that keep the current feature >>> smaller >>> while allowing room for a broader feature later. >>> >>> Some worked examples of the sets of thrown exceptions types under >>> various >>> tricky code samples would help clarify the data flow algorithm for >>> me. >> >> Sure, I can do that. ?Do you think that should go in the >> specification? >> >>>> A catch clause is currently compiled (before this change) to an >>>> entry >>>> in an exception table that specifies the type of the exception and >>>> the >>>> address of the code for the catch body. To generate code for this >>>> new >>>> construct, the compiler would generate an entry in the exception >>>> table >>>> for each type in the exception parameter's list of types. >>>> >>> >>> Interesting; so there would be no code duplication even in the >>> class files. >> >> Correct. ?That's what the current prototype (in the BGGA compiler) >> does for this construct. >> >>> How could the increased exception precision be maintained will >>> still allow >>> programs such as the one above to compile? >> >> I don't think it can without making rather complex rules, but I'll >> think about it more. >> >> However, one could take only the multicatch part of this proposal and >> not the final/rethrow part, and then I believe one could specify it >> without there being a breaking change. >> > > > From rssh at gradsoft.com.ua Tue Mar 3 07:23:56 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Tue, 3 Mar 2009 17:23:56 +0200 (EET) Subject: PROPOSAL: String literals: version 1.1 In-Reply-To: References: Message-ID: <9fc1ca7a774a8fb8cad30901eac67bd4.squirrel@wmail.gradsoft.ua> >> String foo= """\""" """ is """ > > Is there really a need for escaping? If users want to escape, they can > still use the regular "" string literals. I'd rather have no escaping at > all. Otherwise, you probably also need to escape the \ if you want the We have row unescaped strings with '' brackets already in this proposal. > string to contain \" at the end. """An example:\\"""". The rule 'The new > string literals don't support any escape sequences' if much better than > 'The new string literals only support the escape sequences \""", which > means """ and \\, which means \\'. > Rule can be formed as: we have two new types of literals: with or without escape sequences. First supports all traditional escape sequences, second have no escape sequences at all. > What about supporting " or "" at the beginning or end of the new string > literals? That would result in """" or """"". Or even """""""" if you push > it to the limits. Wouldn't that be hard on the compiler? > Will try ;) From akuhn at iam.unibe.ch Tue Mar 3 09:03:42 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Tue, 3 Mar 2009 18:03:42 +0100 Subject: (update) Use "default" keyword for default visibility In-Reply-To: <49AD1C0B.3070907@joda.org> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <49AD1C0B.3070907@joda.org> Message-ID: <43577BD5-8BD8-45F0-B190-EB04FBB283C3@iam.unibe.ch> Updated the default visibility proposal PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR(S): Adrian Kuhn OVERVIEW: Allow the "package" keyword to be used as modifier for default visibility. FEATURE SUMMARY: Use "package" keyword for default visibility. MAJOR ADVANTAGE: This change is a "5 cent coin" at best, there are not many advantages beyond improved readability and a more beautiful language definition. However, the benefit of improved readability is not to be underestimated. The missing keyword for default visibility breaks the symmetry of visibility modifiers. The use of package visibility is less obvious than other visibility since an explicit modifier is missing. This decreases readability of source code. For example, omitting any of the three explicit modifiers by mistake (or vice verse mistakingly adding any of the tree) may introduce unexpected behavior which is hard to spot due to the bad readability. MAJOR BENEFIT: Improved readability. MAJOR DISADVANTAGE: Two ways to express the same thing (in compatibility mode). ALTERNATIVES: - Using /*default*/ comments (as often seen) is not an alternative since such comments are not processed by the compiler. - Using a custom-made @Package annotation is feasible (it is what I use now) and can be processed by the compiler using an annotation processor. EXAMPLES SIMPLE EXAMPLE: public class Point { package int x; package int y; } ADVANCED EXAMPLE: package ch.akuhn.util; package class Foo { } DETAILS SPECIFICATION: "package" is already a keyword, introducing it as a new visibility modifier is thus save. To distinguish package visible top-level classes and package declarations, the grammar will need a lookahead of two tokens (I dont know if this is a problem). COMPILATION: Same as now with implicit default visibility. TESTING: Same as now with implicit default visibility. LIBRARY SUPPORT: None. REFLECTIVE APIS: None. OTHER CHANGES: None. MIGRATION: See below, strict vs compatibility mode. COMPATIBILITY: A compiler switch is offered to set either strict or compatibility mode. In strict mode, an error is issued if a member has not visibility modifier. In compatibility mode, members without visibility modifier as treated as default visibile (which is the current semantics of Java). BREAKING CHANGES: None. EXISTING PROGRAMS: Work fine in compatibility mode. REFERENCES EXISTING BUGS: To my best knowledge, none. URL FOR PROTOTYPE (optional): On Mar 3, 2009, at 13:01 , Stephen Colebourne wrote: >> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >> AUTHOR(S): Adrian Kuhn >> OVERVIEW >> Allow the "default" keyword to be used as modifier for default >> visibility. In strict mode, missing use of default is a warning / >> error, in compatibility mode both the current (ie no default >> keyword) and the new syntax are accepted. >> FEATURE SUMMARY: Use "default" keyword for default visibility. >> MAJOR ADVANTAGE: The missing keyword for default visibility breaks >> the symmetry of visibility modifiers. Since it is the only >> implicit modifier, omitting any of the three explicit modifiers by >> mistake may be the source of unexpected behavior and thus hard to >> track down bugs. (There was an example on a blog post recently, >> but I cannot find it know). >> MAJOR BENEFIT: Symmetry of visibility modifiers is restored. >> MAJOR DISADVANTAGE: Two ways to express the same thing (in >> compatibility mode). >> ALTERNATIVES: Using a comment such as /* default */ is not an >> alternative since such comments are not processed by the compiler. >> EXAMPLES >> public class C { >> default Field f; >> } >> SIMPLE EXAMPLE: See above. >> ADVANCED EXAMPLE: None. >> DETAILS >> SPECIFICATION: "default" is already a keyword and introducing it as >> a new visibility modifier is save, it does not lead to ambiguous >> grammar. >> COMPILATION: Same as now for implicit default visibility. >> TESTING: Same as now for implicit default visibility. >> LIBRARY SUPPORT: None. >> REFLECTIVE APIS: None. >> OTHER CHANGES: None. >> MIGRATION: Compatibility mode allows both, implicit and explicit >> default visibility, to be used at the same time. >> COMPATIBILITY >> BREAKING CHANGES: None. >> EXISTING PROGRAMS: Work fine in compatibility mode. >> REFERENCES >> EXISTING BUGS: To my best knowledge, none. >> URL FOR PROTOTYPE (optional): From jjb at google.com Tue Mar 3 10:03:40 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 10:03:40 -0800 Subject: Simple Resource Clean-up In-Reply-To: References: Message-ID: <17b2302a0903031003w17d5611eo339d4c5ef51ac2b1@mail.gmail.com> Roger, Hi. > > The specification requires that the object in the try () block have a > "close()" method. Wether the method throws any or no exception, or if it > returns a value or no value does not matter. This is a "naming pattern" (of the sort used by serialization and beans). If we need more flexibility than interfaces provide, I believe that we're better off going all the way to annotations (see Item 35 in Effective Java, Second Ed.). This would allow us to use the automatic resource management statement with types whose "dispose" method wasn't named close (such as java.awt.graphics.dispose). This is listed as a "design alternative" at the bottom of my proposal. Here's how I summarize the pros and cons: "[Use of an annotation] allows the use of a different method names (such as destroy and terminate) and eases the use of the new construct with existing resource types. But it is more ?magical? and does not mesh as well with Java?s type system." I do see this as a viable alternative, but with pros and cons. I believe it would be relatively straightforward to retrofit my proposal to use method annotations instead of (or in addition to) an interface. Regards, Josh From neal at gafter.com Tue Mar 3 10:47:31 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 10:47:31 -0800 Subject: Simple Resource Clean-up In-Reply-To: <17b2302a0903031003w17d5611eo339d4c5ef51ac2b1@mail.gmail.com> References: <17b2302a0903031003w17d5611eo339d4c5ef51ac2b1@mail.gmail.com> Message-ID: <15e8b9d20903031047q235815d5i669b93575fefba75@mail.gmail.com> This would be the first instance of an annotation that changes the meaning of the language's primitive constructs. Today, this kind of thing is the role of declaration modifiers. We went to great length to discourage this kind of use of annotations in the past; annotations are to annotate the program text (in a way sometimes visible to libraries), not define it. I understand the reluctance to add new keywords to the language, but I advise against adding annotations as language modifiers (essentially, adding modifiers with an "@" prefix). The fact that this kind of flexibility is required suggests the facility should be provided by libraries rather than hardcoded into the language. On Tue, Mar 3, 2009 at 10:03 AM, Joshua Bloch wrote: > Roger, > > Hi. > > >> >> ? The specification requires that the object in the try () block have a >> "close()" method. ?Wether the method throws any or no exception, or if it >> returns a value or no value does not matter. > > > This is a "naming pattern" (of the sort used by serialization and beans). > ?If we need more flexibility than interfaces provide, I believe that we're > better off going all the way to annotations (see Item 35 in Effective Java, > Second Ed.). ? This would allow us to use the automatic resource management > statement with types whose "dispose" method wasn't named close (such as > java.awt.graphics.dispose). This is listed as a "design alternative" at the > bottom of my proposal. > > Here's how I summarize the pros and cons: "[Use of an annotation] allows the > use of a different method names (such as destroy and terminate) and eases > the use of the new construct with existing resource types. But it is more > ?magical? and does not mesh as well with Java?s type system." ?I do see this > as a viable alternative, but with pros and cons. ?I believe it would be > relatively straightforward to retrofit my proposal to use method annotations > instead of (or in addition to) an interface. > > ? ? ? ? ? Regards, > > ? ? ? ? ? Josh > > From jeremy.manson at gmail.com Tue Mar 3 11:31:59 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Tue, 3 Mar 2009 11:31:59 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <49AD1B58.5060305@joda.org> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> <49AD1B58.5060305@joda.org> Message-ID: <1631da7d0903031131y6a97059bw45346448dd87c645@mail.gmail.com> On Tue, Mar 3, 2009 at 3:58 AM, Stephen Colebourne wrote: > Jeremy Manson wrote: >>> The principle perceived disadvantage, however, is that it encourages, >>> rather than discourages, the use of null values in APIs. >> >> I would think that the principle disadvantage would be not that it >> encourages use of null values (which, as you point out, is fine in >> some contexts), but that it encourages programmers not to think about >> what happens when there is a null value. > > But that is exactly what already happens today. Most developers are very > poor at thinking through the null consequences of a method - the happy > day scenario is the one focussed on. Right. This is bad, because much of the time, the program cannot tolerate nulls. >> I can easily imagine >> programmers using this all of the time without thinking about it, and >> then being surprised when a null ends up in the wrong place and not >> knowing how it got there. ?Even with a simple example: >> >> public String someFunction(String a, String b) { >> ? String s = a?.concat("foo"); >> ? String t = b?.concat(a); >> ? return myHashMap?.get(t); >> } >> >> Now, someFunction returns null. ?Is it because a was null? ?Or b was >> null? ?Or myHashMap was null? ?Or there was no mapping for t in >> myHashMap? > > Or perhaps it doesn't matter, and thats why the code was written that > way. Null as 'don't know' or 'don't care' is incredibly common. So, we have two cases: 1) I've done something wrong, in which case "." provides useful semantics, because it is fail fast. 2) "Don't know" or "Don't care", in which case "?." doesn't provide useful semantics, but is less typing. Flipping through a few thousand lines' worth of our source files, I see hundreds of examples of #1, and only a couple of examples of #2. Most of the time, we know a priori that we're not doing a null dereference, so we don't need the ?.. This pretty much gels with my intuition about this. Perhaps it is different in EE code? I would be interested to hear a more thorough study of people's source bases. If it is true that #2 is only responsible for a tiny fraction of the cases in general, then it is a little odd to add a programming language feature around it. (By the way, I'm not denying that it is, as you say, common!) Additionally, every time you use ?., you are going to have to think incredibly carefully about whether it is #1 or #2. And I have this sneaking suspicion that most programmers will just sprinkle it liberally all over their code without thinking about it at all. When they get it wrong, that's going to make errors harder to catch. From a design standpoint, I would lean towards forcing people to think about it every time, because they are more likely to get it right that way. >> If you want to cut down on >> extraneous if-testing, I would use JSR-305's Nullity annotations >> instead. > > What does this code do when passed null? > > Foo f = new Foo(null); > int v = f.value; > > public class Foo { > ? public final Integer value; > ? public Foo(@Nonnull Integer value) { > ? ? this.value = value; > ? } > } > > There is a NPE at f.value, not at new Foo(null). > > You would think that you could never construct an instance of Foo with a > val of null, but you can. The @Nonnull annotation doesn't have any real > meaning unless it is checked using a tool, and javac isn't such a tool. > This will be very confusing when you use Foo from another part of your > application and expect the value to be non-null and get a NPE. In fact > the @Nonnull is positvely misleading. I think that providing warnings for these annotations is a very good idea. That's a language change that makes some sense to me, if the semantics can be nailed down. > Basically, you can't rely on JSR-305. The information needs to be > rechecked. Thus, whats the point in using it at all?!! Documentation > perhaps? Annotations are not suitable for handling language level issues > like nulls. I do think that annotations are suitable for handling language level issues, as long as they are checked. For example, @Override has been very useful to me, because my toolchain complains when I add it and am not overriding something. Jeremy From jeremy.manson at gmail.com Tue Mar 3 11:36:51 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Tue, 3 Mar 2009 11:36:51 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <1631da7d0903031131y6a97059bw45346448dd87c645@mail.gmail.com> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> <49AD1B58.5060305@joda.org> <1631da7d0903031131y6a97059bw45346448dd87c645@mail.gmail.com> Message-ID: <1631da7d0903031136s71593ddcmfc39036d642ccf4b@mail.gmail.com> On Tue, Mar 3, 2009 at 11:31 AM, Jeremy Manson wrote: > Flipping through a few thousand lines' worth of our source files, I > see hundreds of examples of #1, and only a couple of examples of #2. > Most of the time, we know a priori that we're not doing a null > dereference, so we don't need the ?.. ?This pretty much gels with my > intuition about this. ?Perhaps it is different in EE code? ?I would be > interested to hear a more thorough study of people's source bases. ?If > it is true that #2 is only responsible for a tiny fraction of the > cases in general, then it is a little odd to add a programming > language feature around it. I should add to this that most of the cases I found were things like: if (foo != null) { foo.bar(); } That's not really all that compelling. The really compelling case for this feature is: foo.bar().goo().baz().bif(); where each and everyone needs to be null checked, and you want to abandon the computation if any is null. I didn't see any of these at all, but, as I said, this might be different in EE code. Jeremy From Jonathan.Gibbons at Sun.COM Tue Mar 3 11:52:31 2009 From: Jonathan.Gibbons at Sun.COM (Jonathan Gibbons) Date: Tue, 03 Mar 2009 11:52:31 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <1631da7d0903031131y6a97059bw45346448dd87c645@mail.gmail.com> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> <49AD1B58.5060305@joda.org> <1631da7d0903031131y6a97059bw45346448dd87c645@mail.gmail.com> Message-ID: <2EA71BB2-1B19-4D89-B665-9E3DB40E5090@sun.com> Further down, someone wrote: >> >> You would think that you could never construct an instance of Foo >> with a >> val of null, but you can. The @Nonnull annotation doesn't have any >> real >> meaning unless it is checked using a tool, and javac isn't such a >> tool. Well, javac can run annotations processors, and given JSR308, can run processors on more annotations than can exist today, so I would say that javac is a candidate for the tool you are looking for, provided someone can provide the desired annotation processor. -- Jon On Mar 3, 2009, at 11:31 AM, Jeremy Manson wrote: > On Tue, Mar 3, 2009 at 3:58 AM, Stephen Colebourne > wrote: >> Jeremy Manson wrote: >>>> The principle perceived disadvantage, however, is that it >>>> encourages, >>>> rather than discourages, the use of null values in APIs. >>> >>> I would think that the principle disadvantage would be not that it >>> encourages use of null values (which, as you point out, is fine in >>> some contexts), but that it encourages programmers not to think >>> about >>> what happens when there is a null value. >> >> But that is exactly what already happens today. Most developers are >> very >> poor at thinking through the null consequences of a method - the >> happy >> day scenario is the one focussed on. > > Right. This is bad, because much of the time, the program cannot > tolerate nulls. > >>> I can easily imagine >>> programmers using this all of the time without thinking about it, >>> and >>> then being surprised when a null ends up in the wrong place and not >>> knowing how it got there. Even with a simple example: >>> >>> public String someFunction(String a, String b) { >>> String s = a?.concat("foo"); >>> String t = b?.concat(a); >>> return myHashMap?.get(t); >>> } >>> >>> Now, someFunction returns null. Is it because a was null? Or b was >>> null? Or myHashMap was null? Or there was no mapping for t in >>> myHashMap? >> >> Or perhaps it doesn't matter, and thats why the code was written that >> way. Null as 'don't know' or 'don't care' is incredibly common. > > So, we have two cases: > > 1) I've done something wrong, in which case "." provides useful > semantics, because it is fail fast. > > 2) "Don't know" or "Don't care", in which case "?." doesn't provide > useful semantics, but is less typing. > > Flipping through a few thousand lines' worth of our source files, I > see hundreds of examples of #1, and only a couple of examples of #2. > Most of the time, we know a priori that we're not doing a null > dereference, so we don't need the ?.. This pretty much gels with my > intuition about this. Perhaps it is different in EE code? I would be > interested to hear a more thorough study of people's source bases. If > it is true that #2 is only responsible for a tiny fraction of the > cases in general, then it is a little odd to add a programming > language feature around it. > > (By the way, I'm not denying that it is, as you say, common!) > > Additionally, every time you use ?., you are going to have to think > incredibly carefully about whether it is #1 or #2. And I have this > sneaking suspicion that most programmers will just sprinkle it > liberally all over their code without thinking about it at all. When > they get it wrong, that's going to make errors harder to catch. From > a design standpoint, I would lean towards forcing people to think > about it every time, because they are more likely to get it right that > way. > >>> If you want to cut down on >>> extraneous if-testing, I would use JSR-305's Nullity annotations >>> instead. >> >> What does this code do when passed null? >> >> Foo f = new Foo(null); >> int v = f.value; >> >> public class Foo { >> public final Integer value; >> public Foo(@Nonnull Integer value) { >> this.value = value; >> } >> } >> >> There is a NPE at f.value, not at new Foo(null). >> >> You would think that you could never construct an instance of Foo >> with a >> val of null, but you can. The @Nonnull annotation doesn't have any >> real >> meaning unless it is checked using a tool, and javac isn't such a >> tool. >> This will be very confusing when you use Foo from another part of >> your >> application and expect the value to be non-null and get a NPE. In >> fact >> the @Nonnull is positvely misleading. > > I think that providing warnings for these annotations is a very good > idea. That's a language change that makes some sense to me, if the > semantics can be nailed down. > >> Basically, you can't rely on JSR-305. The information needs to be >> rechecked. Thus, whats the point in using it at all?!! Documentation >> perhaps? Annotations are not suitable for handling language level >> issues >> like nulls. > > I do think that annotations are suitable for handling language level > issues, as long as they are checked. For example, @Override has been > very useful to me, because my toolchain complains when I add it and am > not overriding something. > > Jeremy > From reinier at zwitserloot.com Tue Mar 3 12:05:34 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 21:05:34 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903031459.03331.david.goodenough@linkchoose.co.uk> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> Message-ID: <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> You call that lightweight? How about following the beans spec more to the letter and just generate the addPropertyChangeListener, removePropertyChangeListener, setX(), and get/isX() method in response to seeing a keyword or annotation on a given field. You'll have to work out the details, but that sounds far, far simpler to understand. You'll need to flesh this out, but it would look something like: public class Foo { private property int x; } Which would generate the addPropertyChangeListener, removePropertyChangeListener, setX, getX methods, all public, along with the required infrastructure to make it tick. If you don't like the generation, for example because you want the setter to be package private, you just add the setter in the source file; the keyword will only generate the missing stuff. It doesn't cover every use case, but there's always the alternative of doing whatever people do now with beans. Something you didn't mention in your proposal, by the way. I think there's also a fully fleshed out property proposal (including a 'property' keyword) out there somewhere. Possibly make a way to opt out of generating the property change listener support, and just the getters/setters. --Reinier Zwitserloot On Mar 3, 2009, at 15:59, David Goodenough wrote: > Below is my proposal for Lightweight Properties. I know that the > syntax > change is an abbomination to some people, but I have tried to reduce > this to its absolute minimum, while still getting a significant > benefit. > > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > > AUTHOR(S): > > David Goodenough, long time Java user. I can be reached at > david.goodenough at linkchoose.co.uk. > > OVERVIEW > > FEATURE SUMMARY: > > Lightweight Property support > > MAJOR ADVANTAGE: > > Both BeansBinding (whether JSR-295 or others such an JFace or the > JGoodies > binding) and the JPA Criteria API currently require field names (as > Strings) > as arguments, which an IDE/compiler can not check. With this > proposal the > strings would be abandoned, and the IDE/compiler will be able to > check the > correctness of the code. > > MAJOR BENEFIT: > > Manual checking no longer required. This proposal introduces a > simple well > defined IDE/compiler checkable solution. > > MAJOR DISADVANTAGE: > > It is a language change, and this seems to upset some people. > > ALTERNATIVES: > > None really, apart from using another language or continuing to use > String > names. The existing solutions all require String names which are > uncheckable. > > EXAMPLES > > Lets assume we have a POJO called foo, of type Foo with a field bar > of type > Bar, which itself has a field of type Jim called jim. > > There are two forms of lightweight properties:- > > 1) foo#bar would be translated by the compiler into:- > > new Property(foo,"bar"); > > while foo#bar#jim would be translated into:- > > new Property(foo,"bar","jim"); > > 2) Foo#bar would be translated into:- > > new Property(Foo.class,"bar"); > > while Foo#bar#jim would be translated into:- > > new Property(Foo.class,"bar","jim"); > > These two forms create (1) a bound Property, or (2) an unbound one. > Bound > Properties are explicitly bound to a particular instance of a class > (in this > case foo), while unbound Properties are templates which can be > applied to any > instance of class Foo. Actually bound properties can also be used as > unbound > properties, but that is a harmless and useful side effect not a > primary > intent. > > The Property class would need to be added (it is appended below), > and should > be added either to the java.beans package or to the > java.lang.reflect package > (with which is probably has more in common). > > Syntactically a "#" can be placed wherever a "." can be placed > (except inside > a number), and the same checks need to be made (that each field to > the right > of a # is a field in the left hand side) as would be made for a ".". > The only > difference is in field visibility - For the "#" any field is > visible, which > follows the model currently available in the Field class with > getDeclaredFields(). It also follows the model that while a field > might be > private and therefore not directly accessible from outside, getters > and > setters can provide access. > > The Property object provides type safe access to the field in the > form of > getters and setters. These come in pairs, one for bound and the > other for > unbound access. So for bound access no object is required to fetch > the value, > for an unbound object the parent object needs to be specified. So if > we > have:- > > Propertyprop = foo#bar; > > we can later say:- > > Bar b = prop.get(); > > or for an unbound one from a second Foo object foo2:- > > Bar b = prop.get(foo2); > > The getters and setters in the Property object will defer to > explicitly coded > getters and setters if present, otherwise they will use the Field > getter and > setter. > > If a setter is not explicitly coded, the implicit setter will look > for a > PropertyChangeSupport object in the parent object of the rightmost > field and > fire a PropertyChangeEvent to that object. > > There are also two Annotations provided by the Property class, > ReadOnly and > WriteOnly. These stop implicit getters and setters from trying to > read/write > the property. > > Talking of Annotations, this notation can also be used to get at the > Annotations for a field. So to test for the presence of an > Annotation Ann on > Foo.bar we would use:- > > if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... > > SIMPLE EXAMPLE: > > To take an example from BeansBinding (taken from Shannon Hickey's > blog):- > > // create a BeanProperty representing a bean's firstName > Property firstP = BeanProperty.create("firstName"); > // Bind Duke's first name to the text property of a Swing JTextField > BeanProperty textP = BeanProperty.create("text"); > Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, > firstP, textfield, textP); > binding.bind(); > > > would instead be written:- > > Binding binding = Bindings.createAutoBinding(READ_WRITE, > duke#firstName, textfield#text); > binding.bind(); > > which of course can be checked by the IDE/compiler, and will not > wait until > run time (not even instantiation time) to show up the error. > > ADVANCED EXAMPLE: > > For a JComboBox (or JList or JTable or JTree) there is a need to map > a list of > objects to the value strings (or column contents). For this we need > to have > an unbound Property which can be applied to each element of the list. > > Duke duke; > Listdukes; > BoundComboBox combo = new > BoundComboBox(dukes,Duke#fullname,this#duke); > > and now the combo box will be populated from the list dukes, and the > display > values in the list will be taken from the fullname field of each Duke > element, and the initial value will be set from the local class > field duke > and any changes to the combo box selected element will be reflected > back to > the duke field. > > DETAILS > > SPECIFICATION: > > This proposal adds a new syntactic element, "#", which can be used > in the same > way that "." can be used to qualify fields within a Java object. > > COMPILATION: > > This proposal requires no change to the class files, and is > implemented by a > simple generation of the required instance using the relevant Property > constructor. Obviously the compiler would have to make sure that the > use that > the property object was being put to (in the examples above the left > hand > side of the assignment) had the correct Generic attributes. > > TESTING: > > How can the feature be tested? > > LIBRARY SUPPORT: > > The new Property class is required (see below). > > REFLECTIVE APIS: > > No changes are required to the reflective APIs although it makes > extensive use > of those APIs. > > OTHER CHANGES: > > No other changes are requires. > > MIGRATION: > > Fortunately there is no code that is formally part of J2SE 6 which > uses such > Properties. There are however two proposals which will need it > (BeansBinding > and JPA Criteria API), but neither of these seem to be destined to > be part of > J2SE 7 (BeansBinding seems to have died the death and the Criteria > API would > be part of the next J2EE which will follow J2SE 7), so this will > provide a > base for them to use and no existing code need to be updated. > > There are other extant Beans-Binding libraries, which could be > modified to use > this proposal, but as none of the existing features have been > changed there > is no need to change them (other than for type safety and compiler/IDE > checkability). > > COMPATIBILITY > > BREAKING CHANGES: > > None. This change should not make any existing correct code fail to > compile > or run or change the way in which it compiles/runs. > > EXISTING PROGRAMS: > > No change required to any existing programs > > REFERENCES > > EXISTING BUGS: > > None > > URL FOR PROTOTYPE (optional): > > I do not have the knowledge to make changes to the compiler, and the > only > documentation making such changes concentrated on adding operators not > changes at this level. So there is no prototype of the compiler > part, but the > Property class follows:- > > package java.lang.reflect; > > import java.beans.BeanInfo; > import java.beans.Introspector; > import java.beans.PropertyChangeSupport; > import java.beans.PropertyDescriptor; > import java.lang.reflect.Field; > import java.lang.reflect.Method; > > /** > * Property class > * This is the support class for use with the # notation to provide > lightweight > * Property support for Java. > * > * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd > * @licence LPGL V2 : details of which can be found at http://fsf.org. > * @author david.goodenough at linkchoose.co.uk > * > * @param The Parent class for this field > * @param The Type of this field > */ > public class Property { > private C parent; > private Class parentClass; > private Field[] fields; > private PropertyDescriptor[] pd = null; > /** > * Constructor used to create Property objects. The Parent object > may be > * null, but should normally be specified as it can be overridden > anyway. > * @param parent C object that contains the field > * @param field Field describing this field > */ > public Property(C parent, String ... fieldNames) { > this.parent = parent; > this(parent.getClass(), fieldNames); > } > /** > * Constructor for unbound Properties, but also used internally > after > setting > * the parent object by the bound Property objects. > * @param parentClass Class of the parent object > * @param fieldNames String[] of field names > */ > public Property(ClassparentClass, String .. fieldNames) { > this.parentClass = parentClass; > fields = new Field[fieldNames.length]; > pd = new PropertyDescriptor[fieldNames.length]; > outer: for(int index = 0; index < fields.length; index++) { > Field[]dclFields = parentClass.getDeclaredFields(); > for(Field field:dclFields) { > if(field.getName().equals(fieldNames[index])) { > fields[index] = field; > field.setAccessible(true); > try { > BeanInfo beanInfo = > Introspector.getBeanInfo(parent.getClass()); > PropertyDescriptor[]props = > beanInfo.getPropertyDescriptors(); > for(PropertyDescriptor prop : props) { > if(prop.getName().equals(field.getName())) { > pd[index] = prop; > break; > } > } > } catch(Exception e) { /* assume can not find getter/ > setter > */ } > parentClass = field.getType(); > continue outer; > } > } > throw new IllegalArgumentException("Field " + fieldNames[index] + > " not found in class " + > parentClass.getCanonicalName()); > } > } > /** > * Getter from the field in the parent specified when this > Property was > created. > * @see Property.get(C otherParent) > * @return F the value of this field > */ > public F get() { > return get(parent); > } > /** > * Getter with explicit parent. > * This code will check see if this field is WriteOnly, and > complain if it > is. > * It will then see if the use has provided am explicit getter, > and call > that > * if present, otherwise it will just fetch the value through the > Field > provided > * method. > * @param otherParent C parent object > * @return F value of the field > */ > @SuppressWarnings("unchecked") // This should actually not be > needed, > // but the Field.get method is not > typed > public F get(C otherParent) { > Object result = otherParent; > try { > for(int index = 0; index < fields.length; index++) { > > if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > throw new IllegalAccessException( > "Can not get from a WriteOnly field - " + > fields[index].getName()); > Method getter = pd[index] == null ? null : > pd[index].getReadMethod(); > if(getter == null) result = fields[index].get(result); > else result = getter.invoke(result); > } > } catch(Exception e) { > throw new RuntimeException("Should not occur exception", e); > } > return (F)result; > } > /** > * Setter to set the value of the field in the parent object > declared with > the > * Property object > * @param newValue F new value of this field > */ > public void set(F newValue) { > set(parent,newValue); > } > /** > * Setter to set the value of the field to an explicit parent > object. > * If there is a ReadOnly annotation, then we object. If there is > an > explicit > * setter then we use that, otherwise we set the field using the > Field > provided > * set method and if there is a PropertyChangeSupport field, fire a > property > * change event to it. > * We walk our way down the field chain, until we have the last > object and > its > * field, and then we do the set. > * @param parent C explicit parent object > * @param newValue F new value for field in parent > */ > public void set(C parent,F newValue) { > try { > Object last = parent; > int index; > for(index = 0; index < fields.length - 1; index++) { > > if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > throw new IllegalAccessException( > "Can not get from a WriteOnly field - " + > fields[index].getName()); > Method getter = pd[index] == null ? null : > pd[index].getReadMethod(); > if(getter == null) last = fields[index].get(last); > else last = getter.invoke(last); > } > > if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) > throw new IllegalAccessException( > "Can not get from a WriteOnly field - " + > fields[index].getName()); > Method setter = pd[index] == null ? null : > pd[index].getWriteMethod(); > if(setter == null) { > PropertyChangeSupport pcs = findPcs(last.getClass()); > fields[index].set(last,newValue); > if(pcs != null) > pcs.firePropertyChange(fields[index].getName(), > newValue, > > fields[index].get(last)); > } else setter.invoke(last,newValue); > } catch(Exception e) { > throw new RuntimeException("Should not occur > exception", e); > } > } > /** > * This is used so that the caller can view the Field name > * @return String field name > */ > public String[] getFieldName() { > String[]names = new String[fields.length]; > for(int index = 0; index < fields.length; index++) { > names[index] = fields[index].getName(); > } > return names; > } > /** > * This method is used to fetch the Field array, which is useful > if you > need to > * access the Annotations of a field. > * @return Field[] the array of Fields describing this Property. > */ > public Field[] getFields() { > return fields; > } > /** > * This private method looks for a PropertyChangeSupport object in > the > class and > * if one is found it will return it. It looks right the way up > the class > tree > * by recurring up the superClasses. > * @param parent Class to check for PropertyChangeSupport fields > * @return PropertyChangeSupport first found object, or null if > not found > */ > private PropertyChangeSupport findPcs(Class parent) { > Field fields[] = parent.getDeclaredFields(); > for(Field field:fields) { > field.setAccessible(true); > try { > if(field.getType() == PropertyChangeSupport.class) > return (PropertyChangeSupport)field.get(parent); > } catch(Exception e) { } > } > // If we did not find it then try the superclass > ClasssuperClass = parent.getSuperclass(); > if(superClass == null) return null; > return findPcs(parent.getClass().getSuperclass()); > } > /** > * This annotation is used to mark a field as WriteOnly, i.e. it > can not > be read. > * This stops the automatic getter operation. > */ > public @interface WriteOnly { > } > /** > * This annotation is used to mark a field as ReadOnly, i.e. it > can not be > written. > * This stops the automatic setter operation. > */ > public @interface ReadOnly { > } > } > From develop4lasu at gmail.com Tue Mar 3 12:17:17 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Tue, 3 Mar 2009 21:17:17 +0100 Subject: 'This' type Message-ID: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> AUTHOR: Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ OVERVIEW FEATURE SUMMARY: This type add ability to project valid interfaces(classes) for further extending/implementing. 'This' means current interface/class type or something implementing/extending it. MAJOR ADVANTAGE: - Support of interface projecting at interface level. - More readable code structure (interfaces/methods). - Making refactor more enjoyable (much easier). - Discarding request of replacing 'void' with 'this'. - Splitting interfaces to sub-interfaces can become pleasant. - Down casting working properly. - Decreasing number of method signatures in classes/interfaces. MAJOR DISADVANTAGE: - Class 'This' may already exist somewhere in code(?) - As so far, it's not been thought over know if there is point of using it for input parameters. - 'This.class' might be a problem for generics, but generally everything depends on how 'This' is interpreted(personally, I think that it should be generic with arguments)(this.getClass()). ALTERNATIVES: Rewriting each method's signature on every class / interface. EXAMPLES public static interface IB implements Iterable { } public static interface IC implements IB { } Would mean(which is impossible now time): public static interface IC implementsIB, Iterable { } public static interface IA { This write(String s); } public static interface IB extends IA { This write(double value); } public abstract static class CC implements IB { This write(int value){ __ ... __ return this; } } public static class CD extends CC { @Override public This write(double value) { __ ... __ return this; } @Override public This write(String s) { __ ... __ return this; } } public static void main(String[] args) { __ CD object = new CD(); __ object.write("Some").write(3).write(3.11); } Nowdays, the same code would look as: public static interface IA { IA write(String s); } public static interface IB extends IA { IB write(double value); @Override IB write(String s); } public abstract static class CC implements IB { CC write(int value){ __ ... __ return this; } @Override public abstract CC write(double value); @Override public abstract CC write(String s); } public static class CD extends CC { @Override public CD write(double value) { __ ... __ return this; } @Override public CD write(String s) { __ ... __ return this; } __ @Override CD write(int value){ __ ... __ return this; } } DETAILS: SPECIFICATION: (I did not have time to analyze this completely.) COMPILATION: With 'This' type is valid: this null ? extends This 'This' should be considered to be able to appear in: return type(yes). input type(yes/no?). method body(yes?). As generic parameter(yes/only if they appear as return types?). List> would mean This but not less than Container This could be reduced to last superclass COMPATIBILITY Only programs where are class/interface named 'This' used can be problem. REFERENCES Notice that considered document does not contain complete analyze of those solutions and can have some lacks. So if you have some questions/advices that it does not fully fit with Project Coin, post it on my blog to discuss: http://lasu2string.blogspot.com/2009/03/this-type.html -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From neal at gafter.com Tue Mar 3 12:17:30 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 12:17:30 -0800 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> Message-ID: <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> Joe Darcy sort of ruled out adding property support in project coin in http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size Regards, Neal On Tue, Mar 3, 2009 at 12:05 PM, Reinier Zwitserloot wrote: > You call that lightweight? > > How about following the beans spec more to the letter and just > generate the addPropertyChangeListener, removePropertyChangeListener, > setX(), and get/isX() method in response to seeing a keyword or > annotation on a given field. You'll have to work out the details, but > that sounds far, far simpler to understand. > > You'll need to flesh this out, but it would look something like: > > public class Foo { > ? ?private property int x; > } > > Which would generate the addPropertyChangeListener, > removePropertyChangeListener, setX, getX methods, all public, along > with the required infrastructure to make it tick. If you don't like > the generation, for example because you want the setter to be package > private, you just add the setter in the source file; the keyword will > only generate the missing stuff. It doesn't cover every use case, but > there's always the alternative of doing whatever people do now with > beans. Something you didn't mention in your proposal, by the way. > > I think there's also a fully fleshed out property proposal (including > a 'property' keyword) out there somewhere. > > Possibly make a way to opt out of generating the property change > listener support, and just the getters/setters. > --Reinier Zwitserloot > > > > On Mar 3, 2009, at 15:59, David Goodenough wrote: > >> Below is my proposal for Lightweight Properties. ?I know that the >> syntax >> change is an abbomination to some people, but I have tried to reduce >> this to its absolute minimum, while still getting a significant >> benefit. >> >> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >> >> AUTHOR(S): >> >> David Goodenough, long time Java user. I can be reached at >> david.goodenough at linkchoose.co.uk. >> >> OVERVIEW >> >> FEATURE SUMMARY: >> >> Lightweight Property support >> >> MAJOR ADVANTAGE: >> >> Both BeansBinding (whether JSR-295 or others such an JFace or the >> JGoodies >> binding) and the JPA Criteria API currently require field names (as >> Strings) >> as arguments, which an IDE/compiler can not check. With this >> proposal the >> strings would be abandoned, and the IDE/compiler will be able to >> check the >> correctness of the code. >> >> MAJOR BENEFIT: >> >> Manual checking no longer required. This proposal introduces a >> simple well >> defined IDE/compiler checkable solution. >> >> MAJOR DISADVANTAGE: >> >> It is a language change, and this seems to upset some people. >> >> ALTERNATIVES: >> >> None really, apart from using another language or continuing to use >> String >> names. The existing solutions all require String names which are >> uncheckable. >> >> EXAMPLES >> >> Lets assume we have a POJO called foo, of type Foo with a field bar >> of type >> Bar, which itself has a field of type Jim called jim. >> >> There are two forms of lightweight properties:- >> >> 1) foo#bar would be translated by the compiler into:- >> >> ? ? ? new Property(foo,"bar"); >> >> while foo#bar#jim would be translated into:- >> >> ? ? ? new Property(foo,"bar","jim"); >> >> 2) Foo#bar would be translated into:- >> >> ? ? ? new Property(Foo.class,"bar"); >> >> while Foo#bar#jim would be translated into:- >> >> ? ? ? new Property(Foo.class,"bar","jim"); >> >> These two forms create (1) a bound Property, or (2) an unbound one. >> Bound >> Properties are explicitly bound to a particular instance of a class >> (in this >> case foo), while unbound Properties are templates which can be >> applied to any >> instance of class Foo. Actually bound properties can also be used as >> unbound >> properties, but that is a harmless and useful side effect not a >> primary >> intent. >> >> The Property class would need to be added (it is appended below), >> and should >> be added either to the java.beans package or to the >> java.lang.reflect package >> (with which is probably has more in common). >> >> Syntactically a "#" can be placed wherever a "." can be placed >> (except inside >> a number), and the same checks need to be made (that each field to >> the right >> of a # is a field in the left hand side) as would be made for a ".". >> The only >> difference is in field visibility - For the "#" any field is >> visible, which >> follows the model currently available in the Field class with >> getDeclaredFields(). It also follows the model that while a field >> might be >> private and therefore not directly accessible from outside, getters >> and >> setters can provide access. >> >> The Property object provides type safe access to the field in the >> form of >> getters and setters. These come in pairs, one for bound and the >> other for >> unbound access. So for bound access no object is required to fetch >> the value, >> for an unbound object the parent object needs to be specified. So if >> we >> have:- >> >> ? ? ? Propertyprop = foo#bar; >> >> we can later say:- >> >> ? ? ? Bar b = prop.get(); >> >> or for an unbound one from a second Foo object foo2:- >> >> ? ? ? Bar b = prop.get(foo2); >> >> The getters and setters in the Property object will defer to >> explicitly coded >> getters and setters if present, otherwise they will use the Field >> getter and >> setter. >> >> If a setter is not explicitly coded, the implicit setter will look >> for a >> PropertyChangeSupport object in the parent object of the rightmost >> field and >> fire a PropertyChangeEvent to that object. >> >> There are also two Annotations provided by the Property class, >> ReadOnly and >> WriteOnly. These stop implicit getters and setters from trying to >> read/write >> the property. >> >> Talking of Annotations, this notation can also be used to get at the >> Annotations for a field. So to test for the presence of an >> Annotation Ann on >> Foo.bar we would use:- >> >> ? ? ? if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... >> >> SIMPLE EXAMPLE: >> >> To take an example from BeansBinding (taken from Shannon Hickey's >> blog):- >> >> ? ? ? // create a BeanProperty representing a bean's firstName >> ? ? ? Property firstP = BeanProperty.create("firstName"); >> ? ? ? // Bind Duke's first name to the text property of a Swing JTextField >> ? ? ? BeanProperty textP = BeanProperty.create("text"); >> ? ? ? Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? firstP, textfield, textP); >> ? ? ? binding.bind(); >> >> >> would instead be written:- >> >> ? ? ? Binding binding = Bindings.createAutoBinding(READ_WRITE, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? duke#firstName, textfield#text); >> ? ? ? binding.bind(); >> >> which of course can be checked by the IDE/compiler, and will not >> wait until >> run time (not even instantiation time) to show up the error. >> >> ADVANCED EXAMPLE: >> >> For a JComboBox (or JList or JTable or JTree) there is a need to map >> a list of >> objects to the value strings (or column contents). For this we need >> to have >> an unbound Property which can be applied to each element of the list. >> >> ? ? ? Duke duke; >> ? ? ? Listdukes; >> ? ? ? BoundComboBox combo = new >> BoundComboBox(dukes,Duke#fullname,this#duke); >> >> and now the combo box will be populated from the list dukes, and the >> display >> values in the list will be taken from the fullname field of each Duke >> element, and the initial value will be set from the local class >> field duke >> and any changes to the combo box selected element will be reflected >> back to >> the duke field. >> >> DETAILS >> >> SPECIFICATION: >> >> This proposal adds a new syntactic element, "#", which can be used >> in the same >> way that "." can be used to qualify fields within a Java object. >> >> COMPILATION: >> >> This proposal requires no change to the class files, and is >> implemented by a >> simple generation of the required instance using the relevant Property >> constructor. Obviously the compiler would have to make sure that the >> use that >> the property object was being put to (in the examples above the left >> hand >> side of the assignment) had the correct Generic attributes. >> >> TESTING: >> >> How can the feature be tested? >> >> LIBRARY SUPPORT: >> >> The new Property class is required (see below). >> >> REFLECTIVE APIS: >> >> No changes are required to the reflective APIs although it makes >> extensive use >> of those APIs. >> >> OTHER CHANGES: >> >> No other changes are requires. >> >> MIGRATION: >> >> Fortunately there is no code that is formally part of J2SE 6 which >> uses such >> Properties. There are however two proposals which will need it >> (BeansBinding >> and JPA Criteria API), but neither of these seem to be destined to >> be part of >> J2SE 7 (BeansBinding seems to have died the death and the Criteria >> API would >> be part of the next J2EE which will follow J2SE 7), so this will >> provide a >> base for them to use and no existing code need to be updated. >> >> There are other extant Beans-Binding libraries, which could be >> modified to use >> this proposal, but as none of the existing features have been >> changed there >> is no need to change them (other than for type safety and compiler/IDE >> checkability). >> >> COMPATIBILITY >> >> BREAKING CHANGES: >> >> None. ?This change should not make any existing correct code fail to >> compile >> or run or change the way in which it compiles/runs. >> >> EXISTING PROGRAMS: >> >> No change required to any existing programs >> >> REFERENCES >> >> EXISTING BUGS: >> >> None >> >> URL FOR PROTOTYPE (optional): >> >> I do not have the knowledge to make changes to the compiler, and the >> only >> documentation making such changes concentrated on adding operators not >> changes at this level. So there is no prototype of the compiler >> part, but the >> Property class follows:- >> >> package java.lang.reflect; >> >> import java.beans.BeanInfo; >> import java.beans.Introspector; >> import java.beans.PropertyChangeSupport; >> import java.beans.PropertyDescriptor; >> import java.lang.reflect.Field; >> import java.lang.reflect.Method; >> >> /** >> * Property class >> * This is the support class for use with the # notation to provide >> lightweight >> * Property support for Java. >> * >> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd >> * @licence LPGL V2 : details of which can be found at http://fsf.org. >> * @author david.goodenough at linkchoose.co.uk >> * >> * @param The Parent class for this field >> * @param The Type of this field >> */ >> public class Property { >> ? ?private C parent; >> ? private Class parentClass; >> ? private Field[] fields; >> ? private PropertyDescriptor[] pd = null; >> ? /** >> ? ?* Constructor used to create Property objects. ?The Parent object >> may be >> ? ?* null, but should normally be specified as it can be overridden >> anyway. >> ? ?* @param parent C object that contains the field >> ? ?* @param field Field describing this field >> ? ?*/ >> ? public Property(C parent, String ... fieldNames) { >> ? ? ? this.parent = parent; >> ? ? ? ?this(parent.getClass(), fieldNames); >> ? ? ? ?} >> ? ?/** >> ? ? * Constructor for unbound Properties, but also used internally >> after >> setting >> ? ? * the parent object by the bound Property objects. >> ? ? * @param parentClass Class of the parent object >> ? ? * @param fieldNames String[] of field names >> ? ? */ >> ? ?public Property(ClassparentClass, String .. fieldNames) { >> ? ? ? ?this.parentClass = parentClass; >> ? ? ? fields = new Field[fieldNames.length]; >> ? ? ? pd = new PropertyDescriptor[fieldNames.length]; >> outer: ?for(int index = 0; index < fields.length; index++) { >> ? ? ? ? ? Field[]dclFields = parentClass.getDeclaredFields(); >> ? ? ? ? ? ? ? ? ? for(Field field:dclFields) { >> ? ? ? ? ? ? ? ? ? ? ? if(field.getName().equals(fieldNames[index])) { >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fields[index] = field; >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? field.setAccessible(true); >> ? ? ? ? ? ? ? ? ? ? ? try { >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BeanInfo beanInfo = >> Introspector.getBeanInfo(parent.getClass()); >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PropertyDescriptor[]props = >> beanInfo.getPropertyDescriptors(); >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? for(PropertyDescriptor prop : props) { >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(prop.getName().equals(field.getName())) { >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pd[index] = prop; >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break; >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch(Exception e) { /* assume can not find getter/ >> setter >> */ } >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parentClass = field.getType(); >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue outer; >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } >> ? ? ? ? ? ? ? ? ? ? ? } >> ? ? ? throw new IllegalArgumentException("Field " + fieldNames[index] + >> ? ? ? ? ? ? ? ? ? ? ? ? ? " not found in class " + >> parentClass.getCanonicalName()); >> ? ? ? ? ? ? ? } >> ? ? ? } >> ? /** >> ? ?* Getter from the field in the parent specified when this >> Property was >> created. >> ? ?* @see Property.get(C otherParent) >> ? ?* @return F the value of this field >> ? ?*/ >> ? public F get() { >> ? ? ? return get(parent); >> ? ? ? } >> ? /** >> ? ?* Getter with explicit parent. >> ? ?* This code will check see if this field is WriteOnly, and >> complain if it >> is. >> ? ?* It will then see if the use has provided am explicit getter, >> and call >> that >> ? ?* if present, otherwise it will just fetch the value through the >> Field >> provided >> ? ?* method. >> ? ?* @param otherParent C parent object >> ? ?* @return F value of the field >> ? ?*/ >> ? @SuppressWarnings("unchecked") // This should actually not be >> needed, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// but the Field.get method is not >> typed >> ? public F get(C otherParent) { >> ? ? ? Object result = otherParent; >> ? ? ? try { >> ? ? ? ? ? for(int index = 0; index < fields.length; index++) { >> >> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >> ? ? ? ? ? ? ? ? ? throw new IllegalAccessException( >> ? ? ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + >> fields[index].getName()); >> ? ? ? ? ? ? ? Method getter = pd[index] == null ? null : >> pd[index].getReadMethod(); >> ? ? ? ? ? ? ? if(getter == null) result = fields[index].get(result); >> ? ? ? ? ? ? ? ? ? else result = getter.invoke(result); >> ? ? ? ? ? ? ? } >> ? ? ? ? ? } catch(Exception e) { >> ? ? ? ? ? ? ? throw new RuntimeException("Should not occur exception", e); >> ? ? ? ? ? ? ? } >> ? ? ? return (F)result; >> ? ? ? } >> ? /** >> ? ?* Setter to set the value of the field in the parent object >> declared with >> the >> ? ?* Property object >> ? ?* @param newValue F new value of this field >> ? ?*/ >> ? public void set(F newValue) { >> ? ? ? set(parent,newValue); >> ? ? ? } >> ? /** >> ? ?* Setter to set the value of the field to an explicit parent >> object. >> ? ?* If there is a ReadOnly annotation, then we object. ?If there is >> an >> explicit >> ? ?* setter then we use that, otherwise we set the field using the >> Field >> provided >> ? ?* set method and if there is a PropertyChangeSupport field, fire a >> property >> ? ?* change event to it. >> ? ?* We walk our way down the field chain, until we have the last >> object and >> its >> ? ?* field, and then we do the set. >> ? ?* @param parent C explicit parent object >> ? ?* @param newValue F new value for field in parent >> ? ?*/ >> ? public void set(C parent,F newValue) { >> ? ? ? try { >> ? ? ? ? ? Object last = parent; >> ? ? ? ? ? int index; >> ? ? ? ? ? for(index = 0; index < fields.length - 1; index++) { >> >> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >> ? ? ? ? ? ? ? ? ? throw new IllegalAccessException( >> ? ? ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + >> ? ? ? ? ? ? ? ? ? ? ? fields[index].getName()); >> ? ? ? ? ? ? ? Method getter = pd[index] == null ? null : >> pd[index].getReadMethod(); >> ? ? ? ? ? ? ? if(getter == null) last = fields[index].get(last); >> ? ? ? ? ? ? ? else last = getter.invoke(last); >> ? ? ? ? ? ? ? } >> >> if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) >> ? ? ? ? ? ? ? throw new IllegalAccessException( >> ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + >> fields[index].getName()); >> ? ? ? ? ? ? ? Method setter = pd[index] == null ? null : >> pd[index].getWriteMethod(); >> ? ? ? ? ? ? ? if(setter == null) { >> ? ? ? ? ? ? ? ? ? PropertyChangeSupport pcs = findPcs(last.getClass()); >> ? ? ? ? ? ? ? ? ? fields[index].set(last,newValue); >> ? ? ? ? ? ? ? if(pcs != null) >> pcs.firePropertyChange(fields[index].getName(), >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? newValue, >> >> fields[index].get(last)); >> ? ? ? ? ? ? ? } else setter.invoke(last,newValue); >> ? ? ? ? ? } catch(Exception e) { >> ? ? ? ? ? ? ? throw new RuntimeException("Should not occur >> exception", e); >> ? ? ? ? ? ? ? } >> ? ? ? } >> ? /** >> ? ?* This is used so that the caller can view the Field name >> ? ?* @return String field name >> ? ?*/ >> ? public String[] getFieldName() { >> ? ? ? String[]names = new String[fields.length]; >> ? ? ? for(int index = 0; index < fields.length; index++) { >> ? ? ? ? ? names[index] = fields[index].getName(); >> ? ? ? ? ? } >> ? ? ? return names; >> ? ? ? } >> ? ?/** >> ? ? * This method is used to fetch the Field array, which is useful >> if you >> need to >> ? ? * access the Annotations of a field. >> ? ? * @return Field[] the array of Fields describing this Property. >> ? ? */ >> ? ?public Field[] getFields() { >> ? ? ? ?return fields; >> ? ? ? ?} >> ? /** >> ? ?* This private method looks for a PropertyChangeSupport object in >> the >> class and >> ? ?* if one is found it will return it. ?It looks right the way up >> the class >> tree >> ? ?* by recurring up the superClasses. >> ? ?* @param parent Class to check for PropertyChangeSupport fields >> ? ?* @return PropertyChangeSupport first found object, or null if >> not found >> ? ?*/ >> ? private PropertyChangeSupport findPcs(Class parent) { >> ? ? ? Field fields[] = parent.getDeclaredFields(); >> ? ? ? for(Field field:fields) { >> ? ? ? ? ? field.setAccessible(true); >> ? ? ? ? ? try { >> ? ? ? ? ? ? ? if(field.getType() == PropertyChangeSupport.class) >> ? ? ? ? ? ? ? ? ? return (PropertyChangeSupport)field.get(parent); >> ? ? ? ? ? ? ? } catch(Exception e) { } >> ? ? ? ? ? } >> ? ? ? // If we did not find it then try the superclass >> ? ? ? ClasssuperClass = parent.getSuperclass(); >> ? ? ? if(superClass == null) return null; >> ? ? ? return findPcs(parent.getClass().getSuperclass()); >> ? ? ? } >> ? /** >> ? ?* This annotation is used to mark a field as WriteOnly, i.e. it >> can not >> be read. >> ? ?* This stops the automatic getter operation. >> ? ?*/ >> ? public @interface WriteOnly { >> ? ? ? } >> ? /** >> ? ?* This annotation is used to mark a field as ReadOnly, i.e. it >> can not be >> written. >> ? ?* This stops the automatic setter operation. >> ? ?*/ >> ? public @interface ReadOnly { >> ? ? ? } >> ? } >> > > > From neal at gafter.com Tue Mar 3 12:25:54 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 12:25:54 -0800 Subject: 'This' type In-Reply-To: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> Message-ID: <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> I'd love to see the specification, in particular the subtyping rules and modifications to type inference. Once those are in place, I'd like to see an argument that this feature leaves the generic type system sound (i.e. there are no ClassCastExceptions unless there are casts or warnings in the source code). As described in http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size almost any type system change is likely out of scope for project coin. On Tue, Mar 3, 2009 at 12:17 PM, Marek Kozie? wrote: > AUTHOR: Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ > > OVERVIEW > > FEATURE SUMMARY: > This type add ability to project valid interfaces(classes) for further > extending/implementing. 'This' means current interface/class type or > something implementing/extending it. > > > > MAJOR ADVANTAGE: > - Support of interface projecting at interface level. > - More readable code structure (interfaces/methods). > - Making refactor more enjoyable (much easier). > - Discarding request of replacing 'void' with 'this'. > - Splitting interfaces to sub-interfaces can become pleasant. > - Down casting working properly. > - Decreasing number of method signatures in classes/interfaces. > > > MAJOR DISADVANTAGE: > - Class 'This' may already exist somewhere in code(?) > - As so far, it's not been thought over know if there is point of using it > for input parameters. > - 'This.class' might be a problem for generics, but generally everything > depends on how 'This' is interpreted(personally, I think that it should be > generic with arguments)(this.getClass()). > > ALTERNATIVES: > Rewriting each method's signature on every class / interface. > > EXAMPLES > ?public static interface IB implements Iterable { > ?} > > ?public static interface IC implements IB { > ?} > > Would mean(which is impossible now time): > ?public static interface IC implementsIB, Iterable { > ?} > > public static interface IA { > ?This write(String s); > ?} > > ?public static interface IB extends IA { > ?This write(double value); > ?} > > ?public abstract static class CC implements IB { > ?This write(int value){ > __ ?... > __ ?return this; > ?} > ?} > > ?public static class CD extends CC { > ?@Override > ?public This write(double value) { > __ ?... > __ ?return this; > ?} > ?@Override > ?public This write(String s) { > __ ?... > __ ?return this; > ?} > ?} > > ?public static void main(String[] args) { > __ ?CD object = new CD(); > __ ?object.write("Some").write(3).write(3.11); > ?} > > > Nowdays, the same code would look as: > public static interface IA { > ?IA write(String s); > ?} > > ?public static interface IB extends IA { > ?IB write(double value); > ?@Override > ?IB write(String s); > ?} > > ?public abstract static class CC implements IB { > ?CC write(int value){ > __ ?... > __ ?return this; > ?} > > ?@Override > ?public abstract CC write(double value); > > ?@Override > ?public abstract CC write(String s); > ?} > > ?public static class CD extends CC { > ?@Override > ?public CD write(double value) { > __ ?... > __ ?return this; > ?} > ?@Override > ?public CD write(String s) { > __ ?... > __ ?return this; > ?} > __ ?@Override > ?CD write(int value){ > __ ?... > __ ?return this; > ?} > ?} > > DETAILS: > > SPECIFICATION: > (I did not have time to analyze this completely.) > > COMPILATION: > With 'This' type is valid: > this > null > ? extends This > > 'This' should be considered to be able to appear in: > return type(yes). > input type(yes/no?). > method body(yes?). > As generic parameter(yes/only if they appear as return types?). > > List> would mean This but not less than > Container > > This could be reduced to last superclass > > COMPATIBILITY > > Only programs where are class/interface named 'This' used can be problem. > > REFERENCES > > Notice that considered document does not contain complete analyze of those > solutions and can have some lacks. So if you have some questions/advices > that it does not fully fit with Project Coin, post it on my blog to discuss: > http://lasu2string.blogspot.com/2009/03/this-type.html > > > -- > Pozdrowionka. / Regards. > Lasu aka Marek Kozie? > > http://lasu2string.blogspot.com/ > > From develop4lasu at gmail.com Tue Mar 3 12:40:10 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Tue, 3 Mar 2009 21:40:10 +0100 Subject: 'This' type In-Reply-To: <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> Message-ID: <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> W dniu 3 marca 2009 21:25 u?ytkownik Neal Gafter napisa?: > I'd love to see the specification, in particular the subtyping rules > and modifications to type inference. Once those are in place, I'd > like to see an argument that this feature leaves the generic type > system sound (i.e. there are no ClassCastExceptions unless there are > casts or warnings in the source code). As described in > http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size > almost any type system change is likely out of scope for project coin. > > > If we think about it onlt as extension for return types it's quite easy. interface IA{ This method(); } interface IB extends IA { } now: static void some(IB x){ __ x.method() : return type is IB as This for IB; __ ((IA)x).method() : return type is visible as IA as This for IA; } If u have some doubts, just mail the sample (I do not see any reason for valid code to make ClassCastExceptions to appear). -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From neal at gafter.com Tue Mar 3 12:55:04 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 12:55:04 -0800 Subject: 'This' type In-Reply-To: <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> Message-ID: <15e8b9d20903031255i70d719dbgd9f3615c3abe7f11@mail.gmail.com> Not seeing a problem is not the same thing as demonstrating that no problem can occur. One set of problems arise when you use "This" in a superclass type argument, as you did in an example. I simply don't know what subtype relationships that creates. interface A extends Collection {} After this, is A a subtype of Collection
? On Tue, Mar 3, 2009 at 12:40 PM, Marek Kozie? wrote: > If we think about it onlt as extension for return types it's quite easy. > > interface IA{ This method(); } > > interface IB extends IA { } > now: > > static void some(IB x){ > > __ x.method() : return type is IB as This for IB; > > __ ((IA)x).method() : return type is visible as IA as This for IA; > > } > If u have some doubts, just mail the sample (I do not see any reason for > valid code to make ClassCastExceptions to appear). > > -- > Pozdrowionka. / Regards. > Lasu aka Marek Kozie? > > http://lasu2string.blogspot.com/ > > From david.goodenough at linkchoose.co.uk Tue Mar 3 13:00:40 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Tue, 3 Mar 2009 21:00:40 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> Message-ID: <200903032100.42422.david.goodenough@linkchoose.co.uk> That is why I tried to reduce the problem to a really small one. Just one small substitution in the compiler and one small class. Its much smaller than some of the other suggestions for Coin. David On Tuesday 03 March 2009, Neal Gafter wrote: > Joe Darcy sort of ruled out adding property support in project coin in > http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size > > Regards, > Neal > > On Tue, Mar 3, 2009 at 12:05 PM, Reinier Zwitserloot > > wrote: > > You call that lightweight? > > > > How about following the beans spec more to the letter and just > > generate the addPropertyChangeListener, removePropertyChangeListener, > > setX(), and get/isX() method in response to seeing a keyword or > > annotation on a given field. You'll have to work out the details, but > > that sounds far, far simpler to understand. > > > > You'll need to flesh this out, but it would look something like: > > > > public class Foo { > > ? ?private property int x; > > } > > > > Which would generate the addPropertyChangeListener, > > removePropertyChangeListener, setX, getX methods, all public, along > > with the required infrastructure to make it tick. If you don't like > > the generation, for example because you want the setter to be package > > private, you just add the setter in the source file; the keyword will > > only generate the missing stuff. It doesn't cover every use case, but > > there's always the alternative of doing whatever people do now with > > beans. Something you didn't mention in your proposal, by the way. > > > > I think there's also a fully fleshed out property proposal (including > > a 'property' keyword) out there somewhere. > > > > Possibly make a way to opt out of generating the property change > > listener support, and just the getters/setters. > > --Reinier Zwitserloot > > > > On Mar 3, 2009, at 15:59, David Goodenough wrote: > >> Below is my proposal for Lightweight Properties. ?I know that the > >> syntax > >> change is an abbomination to some people, but I have tried to reduce > >> this to its absolute minimum, while still getting a significant > >> benefit. > >> > >> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > >> > >> AUTHOR(S): > >> > >> David Goodenough, long time Java user. I can be reached at > >> david.goodenough at linkchoose.co.uk. > >> > >> OVERVIEW > >> > >> FEATURE SUMMARY: > >> > >> Lightweight Property support > >> > >> MAJOR ADVANTAGE: > >> > >> Both BeansBinding (whether JSR-295 or others such an JFace or the > >> JGoodies > >> binding) and the JPA Criteria API currently require field names (as > >> Strings) > >> as arguments, which an IDE/compiler can not check. With this > >> proposal the > >> strings would be abandoned, and the IDE/compiler will be able to > >> check the > >> correctness of the code. > >> > >> MAJOR BENEFIT: > >> > >> Manual checking no longer required. This proposal introduces a > >> simple well > >> defined IDE/compiler checkable solution. > >> > >> MAJOR DISADVANTAGE: > >> > >> It is a language change, and this seems to upset some people. > >> > >> ALTERNATIVES: > >> > >> None really, apart from using another language or continuing to use > >> String > >> names. The existing solutions all require String names which are > >> uncheckable. > >> > >> EXAMPLES > >> > >> Lets assume we have a POJO called foo, of type Foo with a field bar > >> of type > >> Bar, which itself has a field of type Jim called jim. > >> > >> There are two forms of lightweight properties:- > >> > >> 1) foo#bar would be translated by the compiler into:- > >> > >> ? ? ? new Property(foo,"bar"); > >> > >> while foo#bar#jim would be translated into:- > >> > >> ? ? ? new Property(foo,"bar","jim"); > >> > >> 2) Foo#bar would be translated into:- > >> > >> ? ? ? new Property(Foo.class,"bar"); > >> > >> while Foo#bar#jim would be translated into:- > >> > >> ? ? ? new Property(Foo.class,"bar","jim"); > >> > >> These two forms create (1) a bound Property, or (2) an unbound one. > >> Bound > >> Properties are explicitly bound to a particular instance of a class > >> (in this > >> case foo), while unbound Properties are templates which can be > >> applied to any > >> instance of class Foo. Actually bound properties can also be used as > >> unbound > >> properties, but that is a harmless and useful side effect not a > >> primary > >> intent. > >> > >> The Property class would need to be added (it is appended below), > >> and should > >> be added either to the java.beans package or to the > >> java.lang.reflect package > >> (with which is probably has more in common). > >> > >> Syntactically a "#" can be placed wherever a "." can be placed > >> (except inside > >> a number), and the same checks need to be made (that each field to > >> the right > >> of a # is a field in the left hand side) as would be made for a ".". > >> The only > >> difference is in field visibility - For the "#" any field is > >> visible, which > >> follows the model currently available in the Field class with > >> getDeclaredFields(). It also follows the model that while a field > >> might be > >> private and therefore not directly accessible from outside, getters > >> and > >> setters can provide access. > >> > >> The Property object provides type safe access to the field in the > >> form of > >> getters and setters. These come in pairs, one for bound and the > >> other for > >> unbound access. So for bound access no object is required to fetch > >> the value, > >> for an unbound object the parent object needs to be specified. So if > >> we > >> have:- > >> > >> ? ? ? Propertyprop = foo#bar; > >> > >> we can later say:- > >> > >> ? ? ? Bar b = prop.get(); > >> > >> or for an unbound one from a second Foo object foo2:- > >> > >> ? ? ? Bar b = prop.get(foo2); > >> > >> The getters and setters in the Property object will defer to > >> explicitly coded > >> getters and setters if present, otherwise they will use the Field > >> getter and > >> setter. > >> > >> If a setter is not explicitly coded, the implicit setter will look > >> for a > >> PropertyChangeSupport object in the parent object of the rightmost > >> field and > >> fire a PropertyChangeEvent to that object. > >> > >> There are also two Annotations provided by the Property class, > >> ReadOnly and > >> WriteOnly. These stop implicit getters and setters from trying to > >> read/write > >> the property. > >> > >> Talking of Annotations, this notation can also be used to get at the > >> Annotations for a field. So to test for the presence of an > >> Annotation Ann on > >> Foo.bar we would use:- > >> > >> ? ? ? if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... > >> > >> SIMPLE EXAMPLE: > >> > >> To take an example from BeansBinding (taken from Shannon Hickey's > >> blog):- > >> > >> ? ? ? // create a BeanProperty representing a bean's firstName > >> ? ? ? Property firstP = BeanProperty.create("firstName"); > >> ? ? ? // Bind Duke's first name to the text property of a Swing > >> JTextField BeanProperty textP = BeanProperty.create("text"); > >> ? ? ? Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? firstP, textfield, textP); > >> ? ? ? binding.bind(); > >> > >> > >> would instead be written:- > >> > >> ? ? ? Binding binding = Bindings.createAutoBinding(READ_WRITE, > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? duke#firstName, textfield#text); > >> ? ? ? binding.bind(); > >> > >> which of course can be checked by the IDE/compiler, and will not > >> wait until > >> run time (not even instantiation time) to show up the error. > >> > >> ADVANCED EXAMPLE: > >> > >> For a JComboBox (or JList or JTable or JTree) there is a need to map > >> a list of > >> objects to the value strings (or column contents). For this we need > >> to have > >> an unbound Property which can be applied to each element of the list. > >> > >> ? ? ? Duke duke; > >> ? ? ? Listdukes; > >> ? ? ? BoundComboBox combo = new > >> BoundComboBox(dukes,Duke#fullname,this#duke); > >> > >> and now the combo box will be populated from the list dukes, and the > >> display > >> values in the list will be taken from the fullname field of each Duke > >> element, and the initial value will be set from the local class > >> field duke > >> and any changes to the combo box selected element will be reflected > >> back to > >> the duke field. > >> > >> DETAILS > >> > >> SPECIFICATION: > >> > >> This proposal adds a new syntactic element, "#", which can be used > >> in the same > >> way that "." can be used to qualify fields within a Java object. > >> > >> COMPILATION: > >> > >> This proposal requires no change to the class files, and is > >> implemented by a > >> simple generation of the required instance using the relevant Property > >> constructor. Obviously the compiler would have to make sure that the > >> use that > >> the property object was being put to (in the examples above the left > >> hand > >> side of the assignment) had the correct Generic attributes. > >> > >> TESTING: > >> > >> How can the feature be tested? > >> > >> LIBRARY SUPPORT: > >> > >> The new Property class is required (see below). > >> > >> REFLECTIVE APIS: > >> > >> No changes are required to the reflective APIs although it makes > >> extensive use > >> of those APIs. > >> > >> OTHER CHANGES: > >> > >> No other changes are requires. > >> > >> MIGRATION: > >> > >> Fortunately there is no code that is formally part of J2SE 6 which > >> uses such > >> Properties. There are however two proposals which will need it > >> (BeansBinding > >> and JPA Criteria API), but neither of these seem to be destined to > >> be part of > >> J2SE 7 (BeansBinding seems to have died the death and the Criteria > >> API would > >> be part of the next J2EE which will follow J2SE 7), so this will > >> provide a > >> base for them to use and no existing code need to be updated. > >> > >> There are other extant Beans-Binding libraries, which could be > >> modified to use > >> this proposal, but as none of the existing features have been > >> changed there > >> is no need to change them (other than for type safety and compiler/IDE > >> checkability). > >> > >> COMPATIBILITY > >> > >> BREAKING CHANGES: > >> > >> None. ?This change should not make any existing correct code fail to > >> compile > >> or run or change the way in which it compiles/runs. > >> > >> EXISTING PROGRAMS: > >> > >> No change required to any existing programs > >> > >> REFERENCES > >> > >> EXISTING BUGS: > >> > >> None > >> > >> URL FOR PROTOTYPE (optional): > >> > >> I do not have the knowledge to make changes to the compiler, and the > >> only > >> documentation making such changes concentrated on adding operators not > >> changes at this level. So there is no prototype of the compiler > >> part, but the > >> Property class follows:- > >> > >> package java.lang.reflect; > >> > >> import java.beans.BeanInfo; > >> import java.beans.Introspector; > >> import java.beans.PropertyChangeSupport; > >> import java.beans.PropertyDescriptor; > >> import java.lang.reflect.Field; > >> import java.lang.reflect.Method; > >> > >> /** > >> * Property class > >> * This is the support class for use with the # notation to provide > >> lightweight > >> * Property support for Java. > >> * > >> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd > >> * @licence LPGL V2 : details of which can be found at http://fsf.org. > >> * @author david.goodenough at linkchoose.co.uk > >> * > >> * @param The Parent class for this field > >> * @param The Type of this field > >> */ > >> public class Property { > >> ? ?private C parent; > >> ? private Class parentClass; > >> ? private Field[] fields; > >> ? private PropertyDescriptor[] pd = null; > >> ? /** > >> ? ?* Constructor used to create Property objects. ?The Parent object > >> may be > >> ? ?* null, but should normally be specified as it can be overridden > >> anyway. > >> ? ?* @param parent C object that contains the field > >> ? ?* @param field Field describing this field > >> ? ?*/ > >> ? public Property(C parent, String ... fieldNames) { > >> ? ? ? this.parent = parent; > >> ? ? ? ?this(parent.getClass(), fieldNames); > >> ? ? ? ?} > >> ? ?/** > >> ? ? * Constructor for unbound Properties, but also used internally > >> after > >> setting > >> ? ? * the parent object by the bound Property objects. > >> ? ? * @param parentClass Class of the parent object > >> ? ? * @param fieldNames String[] of field names > >> ? ? */ > >> ? ?public Property(ClassparentClass, String .. fieldNames) { > >> ? ? ? ?this.parentClass = parentClass; > >> ? ? ? fields = new Field[fieldNames.length]; > >> ? ? ? pd = new PropertyDescriptor[fieldNames.length]; > >> outer: ?for(int index = 0; index < fields.length; index++) { > >> ? ? ? ? ? Field[]dclFields = parentClass.getDeclaredFields(); > >> ? ? ? ? ? ? ? ? ? for(Field field:dclFields) { > >> ? ? ? ? ? ? ? ? ? ? ? if(field.getName().equals(fieldNames[index])) { > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fields[index] = field; > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? field.setAccessible(true); > >> ? ? ? ? ? ? ? ? ? ? ? try { > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BeanInfo beanInfo = > >> Introspector.getBeanInfo(parent.getClass()); > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PropertyDescriptor[]props = > >> beanInfo.getPropertyDescriptors(); > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? for(PropertyDescriptor prop : props) { > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? > >> if(prop.getName().equals(field.getName())) { pd[index] = prop; break; > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch(Exception e) { /* assume can not > >> find getter/ setter > >> */ } > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parentClass = field.getType(); > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue outer; > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } > >> ? ? ? ? ? ? ? ? ? ? ? } > >> ? ? ? throw new IllegalArgumentException("Field " + fieldNames[index] + > >> ? ? ? ? ? ? ? ? ? ? ? ? ? " not found in class " + > >> parentClass.getCanonicalName()); > >> ? ? ? ? ? ? ? } > >> ? ? ? } > >> ? /** > >> ? ?* Getter from the field in the parent specified when this > >> Property was > >> created. > >> ? ?* @see Property.get(C otherParent) > >> ? ?* @return F the value of this field > >> ? ?*/ > >> ? public F get() { > >> ? ? ? return get(parent); > >> ? ? ? } > >> ? /** > >> ? ?* Getter with explicit parent. > >> ? ?* This code will check see if this field is WriteOnly, and > >> complain if it > >> is. > >> ? ?* It will then see if the use has provided am explicit getter, > >> and call > >> that > >> ? ?* if present, otherwise it will just fetch the value through the > >> Field > >> provided > >> ? ?* method. > >> ? ?* @param otherParent C parent object > >> ? ?* @return F value of the field > >> ? ?*/ > >> ? @SuppressWarnings("unchecked") // This should actually not be > >> needed, > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// but the Field.get method is not > >> typed > >> ? public F get(C otherParent) { > >> ? ? ? Object result = otherParent; > >> ? ? ? try { > >> ? ? ? ? ? for(int index = 0; index < fields.length; index++) { > >> > >> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > >> ? ? ? ? ? ? ? ? ? throw new IllegalAccessException( > >> ? ? ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + > >> fields[index].getName()); > >> ? ? ? ? ? ? ? Method getter = pd[index] == null ? null : > >> pd[index].getReadMethod(); > >> ? ? ? ? ? ? ? if(getter == null) result = fields[index].get(result); > >> ? ? ? ? ? ? ? ? ? else result = getter.invoke(result); > >> ? ? ? ? ? ? ? } > >> ? ? ? ? ? } catch(Exception e) { > >> ? ? ? ? ? ? ? throw new RuntimeException("Should not occur exception", > >> e); } > >> ? ? ? return (F)result; > >> ? ? ? } > >> ? /** > >> ? ?* Setter to set the value of the field in the parent object > >> declared with > >> the > >> ? ?* Property object > >> ? ?* @param newValue F new value of this field > >> ? ?*/ > >> ? public void set(F newValue) { > >> ? ? ? set(parent,newValue); > >> ? ? ? } > >> ? /** > >> ? ?* Setter to set the value of the field to an explicit parent > >> object. > >> ? ?* If there is a ReadOnly annotation, then we object. ?If there is > >> an > >> explicit > >> ? ?* setter then we use that, otherwise we set the field using the > >> Field > >> provided > >> ? ?* set method and if there is a PropertyChangeSupport field, fire a > >> property > >> ? ?* change event to it. > >> ? ?* We walk our way down the field chain, until we have the last > >> object and > >> its > >> ? ?* field, and then we do the set. > >> ? ?* @param parent C explicit parent object > >> ? ?* @param newValue F new value for field in parent > >> ? ?*/ > >> ? public void set(C parent,F newValue) { > >> ? ? ? try { > >> ? ? ? ? ? Object last = parent; > >> ? ? ? ? ? int index; > >> ? ? ? ? ? for(index = 0; index < fields.length - 1; index++) { > >> > >> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > >> ? ? ? ? ? ? ? ? ? throw new IllegalAccessException( > >> ? ? ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + > >> ? ? ? ? ? ? ? ? ? ? ? fields[index].getName()); > >> ? ? ? ? ? ? ? Method getter = pd[index] == null ? null : > >> pd[index].getReadMethod(); > >> ? ? ? ? ? ? ? if(getter == null) last = fields[index].get(last); > >> ? ? ? ? ? ? ? else last = getter.invoke(last); > >> ? ? ? ? ? ? ? } > >> > >> if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) > >> ? ? ? ? ? ? ? throw new IllegalAccessException( > >> ? ? ? ? ? ? ? ? ? "Can not get from a WriteOnly field - " + > >> fields[index].getName()); > >> ? ? ? ? ? ? ? Method setter = pd[index] == null ? null : > >> pd[index].getWriteMethod(); > >> ? ? ? ? ? ? ? if(setter == null) { > >> ? ? ? ? ? ? ? ? ? PropertyChangeSupport pcs = findPcs(last.getClass()); > >> ? ? ? ? ? ? ? ? ? fields[index].set(last,newValue); > >> ? ? ? ? ? ? ? if(pcs != null) > >> pcs.firePropertyChange(fields[index].getName(), > >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? newValue, > >> > >> fields[index].get(last)); > >> ? ? ? ? ? ? ? } else setter.invoke(last,newValue); > >> ? ? ? ? ? } catch(Exception e) { > >> ? ? ? ? ? ? ? throw new RuntimeException("Should not occur > >> exception", e); > >> ? ? ? ? ? ? ? } > >> ? ? ? } > >> ? /** > >> ? ?* This is used so that the caller can view the Field name > >> ? ?* @return String field name > >> ? ?*/ > >> ? public String[] getFieldName() { > >> ? ? ? String[]names = new String[fields.length]; > >> ? ? ? for(int index = 0; index < fields.length; index++) { > >> ? ? ? ? ? names[index] = fields[index].getName(); > >> ? ? ? ? ? } > >> ? ? ? return names; > >> ? ? ? } > >> ? ?/** > >> ? ? * This method is used to fetch the Field array, which is useful > >> if you > >> need to > >> ? ? * access the Annotations of a field. > >> ? ? * @return Field[] the array of Fields describing this Property. > >> ? ? */ > >> ? ?public Field[] getFields() { > >> ? ? ? ?return fields; > >> ? ? ? ?} > >> ? /** > >> ? ?* This private method looks for a PropertyChangeSupport object in > >> the > >> class and > >> ? ?* if one is found it will return it. ?It looks right the way up > >> the class > >> tree > >> ? ?* by recurring up the superClasses. > >> ? ?* @param parent Class to check for PropertyChangeSupport fields > >> ? ?* @return PropertyChangeSupport first found object, or null if > >> not found > >> ? ?*/ > >> ? private PropertyChangeSupport findPcs(Class parent) { > >> ? ? ? Field fields[] = parent.getDeclaredFields(); > >> ? ? ? for(Field field:fields) { > >> ? ? ? ? ? field.setAccessible(true); > >> ? ? ? ? ? try { > >> ? ? ? ? ? ? ? if(field.getType() == PropertyChangeSupport.class) > >> ? ? ? ? ? ? ? ? ? return (PropertyChangeSupport)field.get(parent); > >> ? ? ? ? ? ? ? } catch(Exception e) { } > >> ? ? ? ? ? } > >> ? ? ? // If we did not find it then try the superclass > >> ? ? ? ClasssuperClass = parent.getSuperclass(); > >> ? ? ? if(superClass == null) return null; > >> ? ? ? return findPcs(parent.getClass().getSuperclass()); > >> ? ? ? } > >> ? /** > >> ? ?* This annotation is used to mark a field as WriteOnly, i.e. it > >> can not > >> be read. > >> ? ?* This stops the automatic getter operation. > >> ? ?*/ > >> ? public @interface WriteOnly { > >> ? ? ? } > >> ? /** > >> ? ?* This annotation is used to mark a field as ReadOnly, i.e. it > >> can not be > >> written. > >> ? ?* This stops the automatic setter operation. > >> ? ?*/ > >> ? public @interface ReadOnly { > >> ? ? ? } > >> ? } From david.goodenough at linkchoose.co.uk Tue Mar 3 13:04:58 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Tue, 3 Mar 2009 21:04:58 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> Message-ID: <200903032104.58445.david.goodenough@linkchoose.co.uk> Yes I do. What you propose is much more invasive. Look at it again and maybe you will see the Light(ness). David On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > You call that lightweight? > > How about following the beans spec more to the letter and just > generate the addPropertyChangeListener, removePropertyChangeListener, > setX(), and get/isX() method in response to seeing a keyword or > annotation on a given field. You'll have to work out the details, but > that sounds far, far simpler to understand. > > You'll need to flesh this out, but it would look something like: > > public class Foo { > private property int x; > } > > Which would generate the addPropertyChangeListener, > removePropertyChangeListener, setX, getX methods, all public, along > with the required infrastructure to make it tick. If you don't like > the generation, for example because you want the setter to be package > private, you just add the setter in the source file; the keyword will > only generate the missing stuff. It doesn't cover every use case, but > there's always the alternative of doing whatever people do now with > beans. Something you didn't mention in your proposal, by the way. > > I think there's also a fully fleshed out property proposal (including > a 'property' keyword) out there somewhere. > > Possibly make a way to opt out of generating the property change > listener support, and just the getters/setters. > --Reinier Zwitserloot > > On Mar 3, 2009, at 15:59, David Goodenough wrote: > > Below is my proposal for Lightweight Properties. I know that the > > syntax > > change is an abbomination to some people, but I have tried to reduce > > this to its absolute minimum, while still getting a significant > > benefit. > > > > PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > > > > AUTHOR(S): > > > > David Goodenough, long time Java user. I can be reached at > > david.goodenough at linkchoose.co.uk. > > > > OVERVIEW > > > > FEATURE SUMMARY: > > > > Lightweight Property support > > > > MAJOR ADVANTAGE: > > > > Both BeansBinding (whether JSR-295 or others such an JFace or the > > JGoodies > > binding) and the JPA Criteria API currently require field names (as > > Strings) > > as arguments, which an IDE/compiler can not check. With this > > proposal the > > strings would be abandoned, and the IDE/compiler will be able to > > check the > > correctness of the code. > > > > MAJOR BENEFIT: > > > > Manual checking no longer required. This proposal introduces a > > simple well > > defined IDE/compiler checkable solution. > > > > MAJOR DISADVANTAGE: > > > > It is a language change, and this seems to upset some people. > > > > ALTERNATIVES: > > > > None really, apart from using another language or continuing to use > > String > > names. The existing solutions all require String names which are > > uncheckable. > > > > EXAMPLES > > > > Lets assume we have a POJO called foo, of type Foo with a field bar > > of type > > Bar, which itself has a field of type Jim called jim. > > > > There are two forms of lightweight properties:- > > > > 1) foo#bar would be translated by the compiler into:- > > > > new Property(foo,"bar"); > > > > while foo#bar#jim would be translated into:- > > > > new Property(foo,"bar","jim"); > > > > 2) Foo#bar would be translated into:- > > > > new Property(Foo.class,"bar"); > > > > while Foo#bar#jim would be translated into:- > > > > new Property(Foo.class,"bar","jim"); > > > > These two forms create (1) a bound Property, or (2) an unbound one. > > Bound > > Properties are explicitly bound to a particular instance of a class > > (in this > > case foo), while unbound Properties are templates which can be > > applied to any > > instance of class Foo. Actually bound properties can also be used as > > unbound > > properties, but that is a harmless and useful side effect not a > > primary > > intent. > > > > The Property class would need to be added (it is appended below), > > and should > > be added either to the java.beans package or to the > > java.lang.reflect package > > (with which is probably has more in common). > > > > Syntactically a "#" can be placed wherever a "." can be placed > > (except inside > > a number), and the same checks need to be made (that each field to > > the right > > of a # is a field in the left hand side) as would be made for a ".". > > The only > > difference is in field visibility - For the "#" any field is > > visible, which > > follows the model currently available in the Field class with > > getDeclaredFields(). It also follows the model that while a field > > might be > > private and therefore not directly accessible from outside, getters > > and > > setters can provide access. > > > > The Property object provides type safe access to the field in the > > form of > > getters and setters. These come in pairs, one for bound and the > > other for > > unbound access. So for bound access no object is required to fetch > > the value, > > for an unbound object the parent object needs to be specified. So if > > we > > have:- > > > > Propertyprop = foo#bar; > > > > we can later say:- > > > > Bar b = prop.get(); > > > > or for an unbound one from a second Foo object foo2:- > > > > Bar b = prop.get(foo2); > > > > The getters and setters in the Property object will defer to > > explicitly coded > > getters and setters if present, otherwise they will use the Field > > getter and > > setter. > > > > If a setter is not explicitly coded, the implicit setter will look > > for a > > PropertyChangeSupport object in the parent object of the rightmost > > field and > > fire a PropertyChangeEvent to that object. > > > > There are also two Annotations provided by the Property class, > > ReadOnly and > > WriteOnly. These stop implicit getters and setters from trying to > > read/write > > the property. > > > > Talking of Annotations, this notation can also be used to get at the > > Annotations for a field. So to test for the presence of an > > Annotation Ann on > > Foo.bar we would use:- > > > > if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... > > > > SIMPLE EXAMPLE: > > > > To take an example from BeansBinding (taken from Shannon Hickey's > > blog):- > > > > // create a BeanProperty representing a bean's firstName > > Property firstP = BeanProperty.create("firstName"); > > // Bind Duke's first name to the text property of a Swing JTextField > > BeanProperty textP = BeanProperty.create("text"); > > Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, > > firstP, textfield, textP); > > binding.bind(); > > > > > > would instead be written:- > > > > Binding binding = Bindings.createAutoBinding(READ_WRITE, > > duke#firstName, textfield#text); > > binding.bind(); > > > > which of course can be checked by the IDE/compiler, and will not > > wait until > > run time (not even instantiation time) to show up the error. > > > > ADVANCED EXAMPLE: > > > > For a JComboBox (or JList or JTable or JTree) there is a need to map > > a list of > > objects to the value strings (or column contents). For this we need > > to have > > an unbound Property which can be applied to each element of the list. > > > > Duke duke; > > Listdukes; > > BoundComboBox combo = new > > BoundComboBox(dukes,Duke#fullname,this#duke); > > > > and now the combo box will be populated from the list dukes, and the > > display > > values in the list will be taken from the fullname field of each Duke > > element, and the initial value will be set from the local class > > field duke > > and any changes to the combo box selected element will be reflected > > back to > > the duke field. > > > > DETAILS > > > > SPECIFICATION: > > > > This proposal adds a new syntactic element, "#", which can be used > > in the same > > way that "." can be used to qualify fields within a Java object. > > > > COMPILATION: > > > > This proposal requires no change to the class files, and is > > implemented by a > > simple generation of the required instance using the relevant Property > > constructor. Obviously the compiler would have to make sure that the > > use that > > the property object was being put to (in the examples above the left > > hand > > side of the assignment) had the correct Generic attributes. > > > > TESTING: > > > > How can the feature be tested? > > > > LIBRARY SUPPORT: > > > > The new Property class is required (see below). > > > > REFLECTIVE APIS: > > > > No changes are required to the reflective APIs although it makes > > extensive use > > of those APIs. > > > > OTHER CHANGES: > > > > No other changes are requires. > > > > MIGRATION: > > > > Fortunately there is no code that is formally part of J2SE 6 which > > uses such > > Properties. There are however two proposals which will need it > > (BeansBinding > > and JPA Criteria API), but neither of these seem to be destined to > > be part of > > J2SE 7 (BeansBinding seems to have died the death and the Criteria > > API would > > be part of the next J2EE which will follow J2SE 7), so this will > > provide a > > base for them to use and no existing code need to be updated. > > > > There are other extant Beans-Binding libraries, which could be > > modified to use > > this proposal, but as none of the existing features have been > > changed there > > is no need to change them (other than for type safety and compiler/IDE > > checkability). > > > > COMPATIBILITY > > > > BREAKING CHANGES: > > > > None. This change should not make any existing correct code fail to > > compile > > or run or change the way in which it compiles/runs. > > > > EXISTING PROGRAMS: > > > > No change required to any existing programs > > > > REFERENCES > > > > EXISTING BUGS: > > > > None > > > > URL FOR PROTOTYPE (optional): > > > > I do not have the knowledge to make changes to the compiler, and the > > only > > documentation making such changes concentrated on adding operators not > > changes at this level. So there is no prototype of the compiler > > part, but the > > Property class follows:- > > > > package java.lang.reflect; > > > > import java.beans.BeanInfo; > > import java.beans.Introspector; > > import java.beans.PropertyChangeSupport; > > import java.beans.PropertyDescriptor; > > import java.lang.reflect.Field; > > import java.lang.reflect.Method; > > > > /** > > * Property class > > * This is the support class for use with the # notation to provide > > lightweight > > * Property support for Java. > > * > > * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd > > * @licence LPGL V2 : details of which can be found at http://fsf.org. > > * @author david.goodenough at linkchoose.co.uk > > * > > * @param The Parent class for this field > > * @param The Type of this field > > */ > > public class Property { > > private C parent; > > private Class parentClass; > > private Field[] fields; > > private PropertyDescriptor[] pd = null; > > /** > > * Constructor used to create Property objects. The Parent object > > may be > > * null, but should normally be specified as it can be overridden > > anyway. > > * @param parent C object that contains the field > > * @param field Field describing this field > > */ > > public Property(C parent, String ... fieldNames) { > > this.parent = parent; > > this(parent.getClass(), fieldNames); > > } > > /** > > * Constructor for unbound Properties, but also used internally > > after > > setting > > * the parent object by the bound Property objects. > > * @param parentClass Class of the parent object > > * @param fieldNames String[] of field names > > */ > > public Property(ClassparentClass, String .. fieldNames) { > > this.parentClass = parentClass; > > fields = new Field[fieldNames.length]; > > pd = new PropertyDescriptor[fieldNames.length]; > > outer: for(int index = 0; index < fields.length; index++) { > > Field[]dclFields = parentClass.getDeclaredFields(); > > for(Field field:dclFields) { > > if(field.getName().equals(fieldNames[index])) { > > fields[index] = field; > > field.setAccessible(true); > > try { > > BeanInfo beanInfo = > > Introspector.getBeanInfo(parent.getClass()); > > PropertyDescriptor[]props = > > beanInfo.getPropertyDescriptors(); > > for(PropertyDescriptor prop : props) { > > if(prop.getName().equals(field.getName())) { > > pd[index] = prop; > > break; > > } > > } > > } catch(Exception e) { /* assume can not find getter/ > > setter > > */ } > > parentClass = field.getType(); > > continue outer; > > } > > } > > throw new IllegalArgumentException("Field " + fieldNames[index] + > > " not found in class " + > > parentClass.getCanonicalName()); > > } > > } > > /** > > * Getter from the field in the parent specified when this > > Property was > > created. > > * @see Property.get(C otherParent) > > * @return F the value of this field > > */ > > public F get() { > > return get(parent); > > } > > /** > > * Getter with explicit parent. > > * This code will check see if this field is WriteOnly, and > > complain if it > > is. > > * It will then see if the use has provided am explicit getter, > > and call > > that > > * if present, otherwise it will just fetch the value through the > > Field > > provided > > * method. > > * @param otherParent C parent object > > * @return F value of the field > > */ > > @SuppressWarnings("unchecked") // This should actually not be > > needed, > > // but the Field.get method is not > > typed > > public F get(C otherParent) { > > Object result = otherParent; > > try { > > for(int index = 0; index < fields.length; index++) { > > > > if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > > throw new IllegalAccessException( > > "Can not get from a WriteOnly field - " + > > fields[index].getName()); > > Method getter = pd[index] == null ? null : > > pd[index].getReadMethod(); > > if(getter == null) result = fields[index].get(result); > > else result = getter.invoke(result); > > } > > } catch(Exception e) { > > throw new RuntimeException("Should not occur exception", e); > > } > > return (F)result; > > } > > /** > > * Setter to set the value of the field in the parent object > > declared with > > the > > * Property object > > * @param newValue F new value of this field > > */ > > public void set(F newValue) { > > set(parent,newValue); > > } > > /** > > * Setter to set the value of the field to an explicit parent > > object. > > * If there is a ReadOnly annotation, then we object. If there is > > an > > explicit > > * setter then we use that, otherwise we set the field using the > > Field > > provided > > * set method and if there is a PropertyChangeSupport field, fire a > > property > > * change event to it. > > * We walk our way down the field chain, until we have the last > > object and > > its > > * field, and then we do the set. > > * @param parent C explicit parent object > > * @param newValue F new value for field in parent > > */ > > public void set(C parent,F newValue) { > > try { > > Object last = parent; > > int index; > > for(index = 0; index < fields.length - 1; index++) { > > > > if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > > throw new IllegalAccessException( > > "Can not get from a WriteOnly field - " + > > fields[index].getName()); > > Method getter = pd[index] == null ? null : > > pd[index].getReadMethod(); > > if(getter == null) last = fields[index].get(last); > > else last = getter.invoke(last); > > } > > > > if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) > > throw new IllegalAccessException( > > "Can not get from a WriteOnly field - " + > > fields[index].getName()); > > Method setter = pd[index] == null ? null : > > pd[index].getWriteMethod(); > > if(setter == null) { > > PropertyChangeSupport pcs = findPcs(last.getClass()); > > fields[index].set(last,newValue); > > if(pcs != null) > > pcs.firePropertyChange(fields[index].getName(), > > newValue, > > > > fields[index].get(last)); > > } else setter.invoke(last,newValue); > > } catch(Exception e) { > > throw new RuntimeException("Should not occur > > exception", e); > > } > > } > > /** > > * This is used so that the caller can view the Field name > > * @return String field name > > */ > > public String[] getFieldName() { > > String[]names = new String[fields.length]; > > for(int index = 0; index < fields.length; index++) { > > names[index] = fields[index].getName(); > > } > > return names; > > } > > /** > > * This method is used to fetch the Field array, which is useful > > if you > > need to > > * access the Annotations of a field. > > * @return Field[] the array of Fields describing this Property. > > */ > > public Field[] getFields() { > > return fields; > > } > > /** > > * This private method looks for a PropertyChangeSupport object in > > the > > class and > > * if one is found it will return it. It looks right the way up > > the class > > tree > > * by recurring up the superClasses. > > * @param parent Class to check for PropertyChangeSupport fields > > * @return PropertyChangeSupport first found object, or null if > > not found > > */ > > private PropertyChangeSupport findPcs(Class parent) { > > Field fields[] = parent.getDeclaredFields(); > > for(Field field:fields) { > > field.setAccessible(true); > > try { > > if(field.getType() == PropertyChangeSupport.class) > > return (PropertyChangeSupport)field.get(parent); > > } catch(Exception e) { } > > } > > // If we did not find it then try the superclass > > ClasssuperClass = parent.getSuperclass(); > > if(superClass == null) return null; > > return findPcs(parent.getClass().getSuperclass()); > > } > > /** > > * This annotation is used to mark a field as WriteOnly, i.e. it > > can not > > be read. > > * This stops the automatic getter operation. > > */ > > public @interface WriteOnly { > > } > > /** > > * This annotation is used to mark a field as ReadOnly, i.e. it > > can not be > > written. > > * This stops the automatic setter operation. > > */ > > public @interface ReadOnly { > > } > > } From reinier at zwitserloot.com Tue Mar 3 13:15:48 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 22:15:48 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903032104.58445.david.goodenough@linkchoose.co.uk> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> <200903032104.58445.david.goodenough@linkchoose.co.uk> Message-ID: <974754BA-9815-4C98-B868-3D793AFEF79A@zwitserloot.com> The language change required for your proposal is indeed lighter, but to understand it, it is seems a lot more complicated. Also, it would be infeasible to introduce a 'lightweight' (according to anyone's definition) proposal now that is lacking in certain aspects, and then fix it later, unless that fix is syntactically very similar and backwards- and migration compatible. That's the major beef I have with this proposal: It effectively shuts the door on any other property proposal. In my view, a proposal solves the problem properly, or shouldn't be added at all; no quick hacky fixes that aren't part of a planned evolution path to a complete solution. If you can highlight how a complete properties proposal will seamlessly work with your syntax, I'm more inclined to like it. --Reinier Zwitserloot On Mar 3, 2009, at 22:04, David Goodenough wrote: > Yes I do. What you propose is much more invasive. Look at it > again and maybe you will see the Light(ness). > > David > > On Tuesday 03 March 2009, Reinier Zwitserloot wrote: >> You call that lightweight? >> >> How about following the beans spec more to the letter and just >> generate the addPropertyChangeListener, removePropertyChangeListener, >> setX(), and get/isX() method in response to seeing a keyword or >> annotation on a given field. You'll have to work out the details, but >> that sounds far, far simpler to understand. >> >> You'll need to flesh this out, but it would look something like: >> >> public class Foo { >> private property int x; >> } >> >> Which would generate the addPropertyChangeListener, >> removePropertyChangeListener, setX, getX methods, all public, along >> with the required infrastructure to make it tick. If you don't like >> the generation, for example because you want the setter to be package >> private, you just add the setter in the source file; the keyword will >> only generate the missing stuff. It doesn't cover every use case, but >> there's always the alternative of doing whatever people do now with >> beans. Something you didn't mention in your proposal, by the way. >> >> I think there's also a fully fleshed out property proposal (including >> a 'property' keyword) out there somewhere. >> >> Possibly make a way to opt out of generating the property change >> listener support, and just the getters/setters. >> --Reinier Zwitserloot >> >> On Mar 3, 2009, at 15:59, David Goodenough wrote: >>> Below is my proposal for Lightweight Properties. I know that the >>> syntax >>> change is an abbomination to some people, but I have tried to reduce >>> this to its absolute minimum, while still getting a significant >>> benefit. >>> >>> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >>> >>> AUTHOR(S): >>> >>> David Goodenough, long time Java user. I can be reached at >>> david.goodenough at linkchoose.co.uk. >>> >>> OVERVIEW >>> >>> FEATURE SUMMARY: >>> >>> Lightweight Property support >>> >>> MAJOR ADVANTAGE: >>> >>> Both BeansBinding (whether JSR-295 or others such an JFace or the >>> JGoodies >>> binding) and the JPA Criteria API currently require field names (as >>> Strings) >>> as arguments, which an IDE/compiler can not check. With this >>> proposal the >>> strings would be abandoned, and the IDE/compiler will be able to >>> check the >>> correctness of the code. >>> >>> MAJOR BENEFIT: >>> >>> Manual checking no longer required. This proposal introduces a >>> simple well >>> defined IDE/compiler checkable solution. >>> >>> MAJOR DISADVANTAGE: >>> >>> It is a language change, and this seems to upset some people. >>> >>> ALTERNATIVES: >>> >>> None really, apart from using another language or continuing to use >>> String >>> names. The existing solutions all require String names which are >>> uncheckable. >>> >>> EXAMPLES >>> >>> Lets assume we have a POJO called foo, of type Foo with a field bar >>> of type >>> Bar, which itself has a field of type Jim called jim. >>> >>> There are two forms of lightweight properties:- >>> >>> 1) foo#bar would be translated by the compiler into:- >>> >>> new Property(foo,"bar"); >>> >>> while foo#bar#jim would be translated into:- >>> >>> new Property(foo,"bar","jim"); >>> >>> 2) Foo#bar would be translated into:- >>> >>> new Property(Foo.class,"bar"); >>> >>> while Foo#bar#jim would be translated into:- >>> >>> new Property(Foo.class,"bar","jim"); >>> >>> These two forms create (1) a bound Property, or (2) an unbound one. >>> Bound >>> Properties are explicitly bound to a particular instance of a class >>> (in this >>> case foo), while unbound Properties are templates which can be >>> applied to any >>> instance of class Foo. Actually bound properties can also be used as >>> unbound >>> properties, but that is a harmless and useful side effect not a >>> primary >>> intent. >>> >>> The Property class would need to be added (it is appended below), >>> and should >>> be added either to the java.beans package or to the >>> java.lang.reflect package >>> (with which is probably has more in common). >>> >>> Syntactically a "#" can be placed wherever a "." can be placed >>> (except inside >>> a number), and the same checks need to be made (that each field to >>> the right >>> of a # is a field in the left hand side) as would be made for a ".". >>> The only >>> difference is in field visibility - For the "#" any field is >>> visible, which >>> follows the model currently available in the Field class with >>> getDeclaredFields(). It also follows the model that while a field >>> might be >>> private and therefore not directly accessible from outside, getters >>> and >>> setters can provide access. >>> >>> The Property object provides type safe access to the field in the >>> form of >>> getters and setters. These come in pairs, one for bound and the >>> other for >>> unbound access. So for bound access no object is required to fetch >>> the value, >>> for an unbound object the parent object needs to be specified. So if >>> we >>> have:- >>> >>> Propertyprop = foo#bar; >>> >>> we can later say:- >>> >>> Bar b = prop.get(); >>> >>> or for an unbound one from a second Foo object foo2:- >>> >>> Bar b = prop.get(foo2); >>> >>> The getters and setters in the Property object will defer to >>> explicitly coded >>> getters and setters if present, otherwise they will use the Field >>> getter and >>> setter. >>> >>> If a setter is not explicitly coded, the implicit setter will look >>> for a >>> PropertyChangeSupport object in the parent object of the rightmost >>> field and >>> fire a PropertyChangeEvent to that object. >>> >>> There are also two Annotations provided by the Property class, >>> ReadOnly and >>> WriteOnly. These stop implicit getters and setters from trying to >>> read/write >>> the property. >>> >>> Talking of Annotations, this notation can also be used to get at the >>> Annotations for a field. So to test for the presence of an >>> Annotation Ann on >>> Foo.bar we would use:- >>> >>> if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... >>> >>> SIMPLE EXAMPLE: >>> >>> To take an example from BeansBinding (taken from Shannon Hickey's >>> blog):- >>> >>> // create a BeanProperty representing a bean's firstName >>> Property firstP = BeanProperty.create("firstName"); >>> // Bind Duke's first name to the text property of a Swing >>> JTextField >>> BeanProperty textP = BeanProperty.create("text"); >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, >>> firstP, textfield, textP); >>> binding.bind(); >>> >>> >>> would instead be written:- >>> >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, >>> duke#firstName, textfield#text); >>> binding.bind(); >>> >>> which of course can be checked by the IDE/compiler, and will not >>> wait until >>> run time (not even instantiation time) to show up the error. >>> >>> ADVANCED EXAMPLE: >>> >>> For a JComboBox (or JList or JTable or JTree) there is a need to map >>> a list of >>> objects to the value strings (or column contents). For this we need >>> to have >>> an unbound Property which can be applied to each element of the >>> list. >>> >>> Duke duke; >>> Listdukes; >>> BoundComboBox combo = new >>> BoundComboBox(dukes,Duke#fullname,this#duke); >>> >>> and now the combo box will be populated from the list dukes, and the >>> display >>> values in the list will be taken from the fullname field of each >>> Duke >>> element, and the initial value will be set from the local class >>> field duke >>> and any changes to the combo box selected element will be reflected >>> back to >>> the duke field. >>> >>> DETAILS >>> >>> SPECIFICATION: >>> >>> This proposal adds a new syntactic element, "#", which can be used >>> in the same >>> way that "." can be used to qualify fields within a Java object. >>> >>> COMPILATION: >>> >>> This proposal requires no change to the class files, and is >>> implemented by a >>> simple generation of the required instance using the relevant >>> Property >>> constructor. Obviously the compiler would have to make sure that the >>> use that >>> the property object was being put to (in the examples above the left >>> hand >>> side of the assignment) had the correct Generic attributes. >>> >>> TESTING: >>> >>> How can the feature be tested? >>> >>> LIBRARY SUPPORT: >>> >>> The new Property class is required (see below). >>> >>> REFLECTIVE APIS: >>> >>> No changes are required to the reflective APIs although it makes >>> extensive use >>> of those APIs. >>> >>> OTHER CHANGES: >>> >>> No other changes are requires. >>> >>> MIGRATION: >>> >>> Fortunately there is no code that is formally part of J2SE 6 which >>> uses such >>> Properties. There are however two proposals which will need it >>> (BeansBinding >>> and JPA Criteria API), but neither of these seem to be destined to >>> be part of >>> J2SE 7 (BeansBinding seems to have died the death and the Criteria >>> API would >>> be part of the next J2EE which will follow J2SE 7), so this will >>> provide a >>> base for them to use and no existing code need to be updated. >>> >>> There are other extant Beans-Binding libraries, which could be >>> modified to use >>> this proposal, but as none of the existing features have been >>> changed there >>> is no need to change them (other than for type safety and compiler/ >>> IDE >>> checkability). >>> >>> COMPATIBILITY >>> >>> BREAKING CHANGES: >>> >>> None. This change should not make any existing correct code fail to >>> compile >>> or run or change the way in which it compiles/runs. >>> >>> EXISTING PROGRAMS: >>> >>> No change required to any existing programs >>> >>> REFERENCES >>> >>> EXISTING BUGS: >>> >>> None >>> >>> URL FOR PROTOTYPE (optional): >>> >>> I do not have the knowledge to make changes to the compiler, and the >>> only >>> documentation making such changes concentrated on adding operators >>> not >>> changes at this level. So there is no prototype of the compiler >>> part, but the >>> Property class follows:- >>> >>> package java.lang.reflect; >>> >>> import java.beans.BeanInfo; >>> import java.beans.Introspector; >>> import java.beans.PropertyChangeSupport; >>> import java.beans.PropertyDescriptor; >>> import java.lang.reflect.Field; >>> import java.lang.reflect.Method; >>> >>> /** >>> * Property class >>> * This is the support class for use with the # notation to provide >>> lightweight >>> * Property support for Java. >>> * >>> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd >>> * @licence LPGL V2 : details of which can be found at http:// >>> fsf.org. >>> * @author david.goodenough at linkchoose.co.uk >>> * >>> * @param The Parent class for this field >>> * @param The Type of this field >>> */ >>> public class Property { >>> private C parent; >>> private Class parentClass; >>> private Field[] fields; >>> private PropertyDescriptor[] pd = null; >>> /** >>> * Constructor used to create Property objects. The Parent object >>> may be >>> * null, but should normally be specified as it can be overridden >>> anyway. >>> * @param parent C object that contains the field >>> * @param field Field describing this field >>> */ >>> public Property(C parent, String ... fieldNames) { >>> this.parent = parent; >>> this(parent.getClass(), fieldNames); >>> } >>> /** >>> * Constructor for unbound Properties, but also used internally >>> after >>> setting >>> * the parent object by the bound Property objects. >>> * @param parentClass Class of the parent object >>> * @param fieldNames String[] of field names >>> */ >>> public Property(ClassparentClass, String .. fieldNames) { >>> this.parentClass = parentClass; >>> fields = new Field[fieldNames.length]; >>> pd = new PropertyDescriptor[fieldNames.length]; >>> outer: for(int index = 0; index < fields.length; index++) { >>> Field[]dclFields = parentClass.getDeclaredFields(); >>> for(Field field:dclFields) { >>> if(field.getName().equals(fieldNames[index])) { >>> fields[index] = field; >>> field.setAccessible(true); >>> try { >>> BeanInfo beanInfo = >>> Introspector.getBeanInfo(parent.getClass()); >>> PropertyDescriptor[]props = >>> beanInfo.getPropertyDescriptors(); >>> for(PropertyDescriptor prop : props) { >>> if(prop.getName().equals(field.getName())) { >>> pd[index] = prop; >>> break; >>> } >>> } >>> } catch(Exception e) { /* assume can not find getter/ >>> setter >>> */ } >>> parentClass = field.getType(); >>> continue outer; >>> } >>> } >>> throw new IllegalArgumentException("Field " + fieldNames[index] + >>> " not found in class " + >>> parentClass.getCanonicalName()); >>> } >>> } >>> /** >>> * Getter from the field in the parent specified when this >>> Property was >>> created. >>> * @see Property.get(C otherParent) >>> * @return F the value of this field >>> */ >>> public F get() { >>> return get(parent); >>> } >>> /** >>> * Getter with explicit parent. >>> * This code will check see if this field is WriteOnly, and >>> complain if it >>> is. >>> * It will then see if the use has provided am explicit getter, >>> and call >>> that >>> * if present, otherwise it will just fetch the value through the >>> Field >>> provided >>> * method. >>> * @param otherParent C parent object >>> * @return F value of the field >>> */ >>> @SuppressWarnings("unchecked") // This should actually not be >>> needed, >>> // but the Field.get method is not >>> typed >>> public F get(C otherParent) { >>> Object result = otherParent; >>> try { >>> for(int index = 0; index < fields.length; index++) { >>> >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method getter = pd[index] == null ? null : >>> pd[index].getReadMethod(); >>> if(getter == null) result = fields[index].get(result); >>> else result = getter.invoke(result); >>> } >>> } catch(Exception e) { >>> throw new RuntimeException("Should not occur exception", e); >>> } >>> return (F)result; >>> } >>> /** >>> * Setter to set the value of the field in the parent object >>> declared with >>> the >>> * Property object >>> * @param newValue F new value of this field >>> */ >>> public void set(F newValue) { >>> set(parent,newValue); >>> } >>> /** >>> * Setter to set the value of the field to an explicit parent >>> object. >>> * If there is a ReadOnly annotation, then we object. If there is >>> an >>> explicit >>> * setter then we use that, otherwise we set the field using the >>> Field >>> provided >>> * set method and if there is a PropertyChangeSupport field, fire a >>> property >>> * change event to it. >>> * We walk our way down the field chain, until we have the last >>> object and >>> its >>> * field, and then we do the set. >>> * @param parent C explicit parent object >>> * @param newValue F new value for field in parent >>> */ >>> public void set(C parent,F newValue) { >>> try { >>> Object last = parent; >>> int index; >>> for(index = 0; index < fields.length - 1; index++) { >>> >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method getter = pd[index] == null ? null : >>> pd[index].getReadMethod(); >>> if(getter == null) last = fields[index].get(last); >>> else last = getter.invoke(last); >>> } >>> >>> if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method setter = pd[index] == null ? null : >>> pd[index].getWriteMethod(); >>> if(setter == null) { >>> PropertyChangeSupport pcs = findPcs(last.getClass()); >>> fields[index].set(last,newValue); >>> if(pcs != null) >>> pcs.firePropertyChange(fields[index].getName(), >>> newValue, >>> >>> fields[index].get(last)); >>> } else setter.invoke(last,newValue); >>> } catch(Exception e) { >>> throw new RuntimeException("Should not occur >>> exception", e); >>> } >>> } >>> /** >>> * This is used so that the caller can view the Field name >>> * @return String field name >>> */ >>> public String[] getFieldName() { >>> String[]names = new String[fields.length]; >>> for(int index = 0; index < fields.length; index++) { >>> names[index] = fields[index].getName(); >>> } >>> return names; >>> } >>> /** >>> * This method is used to fetch the Field array, which is useful >>> if you >>> need to >>> * access the Annotations of a field. >>> * @return Field[] the array of Fields describing this Property. >>> */ >>> public Field[] getFields() { >>> return fields; >>> } >>> /** >>> * This private method looks for a PropertyChangeSupport object in >>> the >>> class and >>> * if one is found it will return it. It looks right the way up >>> the class >>> tree >>> * by recurring up the superClasses. >>> * @param parent Class to check for PropertyChangeSupport fields >>> * @return PropertyChangeSupport first found object, or null if >>> not found >>> */ >>> private PropertyChangeSupport findPcs(Class parent) { >>> Field fields[] = parent.getDeclaredFields(); >>> for(Field field:fields) { >>> field.setAccessible(true); >>> try { >>> if(field.getType() == PropertyChangeSupport.class) >>> return (PropertyChangeSupport)field.get(parent); >>> } catch(Exception e) { } >>> } >>> // If we did not find it then try the superclass >>> ClasssuperClass = parent.getSuperclass(); >>> if(superClass == null) return null; >>> return findPcs(parent.getClass().getSuperclass()); >>> } >>> /** >>> * This annotation is used to mark a field as WriteOnly, i.e. it >>> can not >>> be read. >>> * This stops the automatic getter operation. >>> */ >>> public @interface WriteOnly { >>> } >>> /** >>> * This annotation is used to mark a field as ReadOnly, i.e. it >>> can not be >>> written. >>> * This stops the automatic setter operation. >>> */ >>> public @interface ReadOnly { >>> } >>> } > > > From develop4lasu at gmail.com Tue Mar 3 13:18:49 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Tue, 3 Mar 2009 22:18:49 +0100 Subject: 'This' type In-Reply-To: <15e8b9d20903031255i70d719dbgd9f3615c3abe7f11@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> <15e8b9d20903031255i70d719dbgd9f3615c3abe7f11@mail.gmail.com> Message-ID: <28bca0ff0903031318h4bbc5d55m734732246de48e0f@mail.gmail.com> W dniu 3 marca 2009 21:55 u?ytkownik Neal Gafter napisa?: > Not seeing a problem is not the same thing as demonstrating that no > problem can occur. One set of problems arise when you use "This" in a > superclass type argument, as you did in an example. I simply don't > know what subtype relationships that creates. > > interface A extends Collection {} > > After this, is A a subtype of Collection? > > On Tue, Mar 3, 2009 at 12:40 PM, Marek Kozie? > wrote: > > If we think about it onlt as extension for return types it's quite easy. > > > > interface IA{ This method(); } > > > > interface IB extends IA { } > > now: > > > > static void some(IB x){ > > > > __ x.method() : return type is IB as This for IB; > > > > __ ((IA)x).method() : return type is visible as IA as This for IA; > > > > } > > If u have some doubts, just mail the sample (I do not see any reason for > > valid code to make ClassCastExceptions to appear). > > > > -- > > Pozdrowionka. / Regards. > > Lasu aka Marek Kozie? > > > > http://lasu2string.blogspot.com/ > > > > > Oh. I get it now. Yes A is a subtype of Collection but after B extends A B will be Collection from B point of view B will be Collection from A point of view In base relation is same as one created by overloaded methods. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From neal at gafter.com Tue Mar 3 13:26:25 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 13:26:25 -0800 Subject: 'This' type In-Reply-To: <28bca0ff0903031318h4bbc5d55m734732246de48e0f@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> <15e8b9d20903031255i70d719dbgd9f3615c3abe7f11@mail.gmail.com> <28bca0ff0903031318h4bbc5d55m734732246de48e0f@mail.gmail.com> Message-ID: <15e8b9d20903031326w47d9bd19ga446312ecc404151@mail.gmail.com> On Tue, Mar 3, 2009 at 1:18 PM, Marek Kozie? wrote: > Oh. > > I get it now. > > Yes A is a subtype of Collection > > but after > > B extends A > > B will be Collection from B point of view > > B will be Collection from A point of view > > In base relation is same as one created by overloaded methods. So if we have a class C that is a sibling of B (a child of A), then from A's point of view we can place a C into the collection (because C is a subtype of A). But then from B's point of view the collection should contain only Bs and not any Cs. So when B pulls something out of the collection we could get a ClassCastException. That's the kind of thing you need to demonstrate can't happen in order to show this change is a sound extension of the type system. From reinier at zwitserloot.com Tue Mar 3 13:33:15 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 3 Mar 2009 22:33:15 +0100 Subject: PROPOSAL: Static Methods in Interfaces Message-ID: Static Methods in Interfaces. See attachment for full proposal in HTML. You can also just look here: http://tinyurl.com/static-methods-in-interfaces -------------- next part -------------- --Reinier Zwitserloot From develop4lasu at gmail.com Tue Mar 3 13:42:47 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Tue, 3 Mar 2009 22:42:47 +0100 Subject: 'This' type In-Reply-To: <15e8b9d20903031326w47d9bd19ga446312ecc404151@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <15e8b9d20903031225l854aaccs90a18038d9e09038@mail.gmail.com> <28bca0ff0903031240v513be89fk8796a76fc8faffa7@mail.gmail.com> <15e8b9d20903031255i70d719dbgd9f3615c3abe7f11@mail.gmail.com> <28bca0ff0903031318h4bbc5d55m734732246de48e0f@mail.gmail.com> <15e8b9d20903031326w47d9bd19ga446312ecc404151@mail.gmail.com> Message-ID: <28bca0ff0903031342w57415d86j90749f5bd4dc0f3c@mail.gmail.com> W dniu 3 marca 2009 22:26 u?ytkownik Neal Gafter napisa?: > On Tue, Mar 3, 2009 at 1:18 PM, Marek Kozie? > wrote: > > Oh. > > > > I get it now. > > > > Yes A is a subtype of Collection > > > > but after > > > > B extends A > > > > B will be Collection from B point of view > > > > B will be Collection from A point of view > > > > In base relation is same as one created by overloaded methods. > > So if we have a class C that is a sibling of B (a child of A), then > from A's point of view we can place a C into the collection (because C > is a subtype of A). But then from B's point of view the collection > should contain only Bs and not any Cs. So when B pulls something out > of the collection we could get a ClassCastException. > > That's the kind of thing you need to demonstrate can't happen in order > to show this change is a sound extension of the type system. > That's the reason why I wander if 'This' should be allowed as input parameter type(what conditions should be respected ...). In basic it's designed for return types and return type parameters. But notice that B b ; A a=b; would be invalid while this comes from generic rules(extends would be partial). -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Tue Mar 3 14:00:27 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Tue, 3 Mar 2009 22:00:27 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <974754BA-9815-4C98-B868-3D793AFEF79A@zwitserloot.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <200903032104.58445.david.goodenough@linkchoose.co.uk> <974754BA-9815-4C98-B868-3D793AFEF79A@zwitserloot.com> Message-ID: <200903032200.28367.david.goodenough@linkchoose.co.uk> Well that depends on what you mean by a complete proposal. There are two parts to the use of Properties. There is the framework side, inside BeansBinding or JPA and then there is the consumer side, the application code. My proposal is very simple on the consumer side (the only bit needed is the # notation). You can use clasical getters and setters (a nuisance but everyone understands them), or the simple getter/setter mechanism that my Property provides. So for the consumer my proposal is real simple. All you need do is add (either explicity or by byte code enhancement) a PropertyChangeSupport object and the relevant methods and you are home and dry. For the Frameworks, well you only write them once. Even so something nice and simple appeals and my proposal is simple. It may not be Beans as we know it, but they never were integrated properly into Java. But its really not that dissimilar just slightly different. So other than a little sytactic sugar (not having to code the PropertyChangeSupport object) we have not really lost anything of the "full" solution. Having a Bound annotation which would add this under the covers with a byte code enhancer would not be difficult. The implicit getters and setters come with the package. So the question to be asked whether a fuller solution is really needed. David On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > The language change required for your proposal is indeed lighter, but > to understand it, it is seems a lot more complicated. > > Also, it would be infeasible to introduce a 'lightweight' (according > to anyone's definition) proposal now that is lacking in certain > aspects, and then fix it later, unless that fix is syntactically very > similar and backwards- and migration compatible. That's the major beef > I have with this proposal: It effectively shuts the door on any other > property proposal. In my view, a proposal solves the problem properly, > or shouldn't be added at all; no quick hacky fixes that aren't part of > a planned evolution path to a complete solution. > > If you can highlight how a complete properties proposal will > seamlessly work with your syntax, I'm more inclined to like it. > > --Reinier Zwitserloot > > On Mar 3, 2009, at 22:04, David Goodenough wrote: > > Yes I do. What you propose is much more invasive. Look at it > > again and maybe you will see the Light(ness). > > > > David > > > > On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > >> You call that lightweight? > >> > >> How about following the beans spec more to the letter and just > >> generate the addPropertyChangeListener, removePropertyChangeListener, > >> setX(), and get/isX() method in response to seeing a keyword or > >> annotation on a given field. You'll have to work out the details, but > >> that sounds far, far simpler to understand. > >> > >> You'll need to flesh this out, but it would look something like: > >> > >> public class Foo { > >> private property int x; > >> } > >> > >> Which would generate the addPropertyChangeListener, > >> removePropertyChangeListener, setX, getX methods, all public, along > >> with the required infrastructure to make it tick. If you don't like > >> the generation, for example because you want the setter to be package > >> private, you just add the setter in the source file; the keyword will > >> only generate the missing stuff. It doesn't cover every use case, but > >> there's always the alternative of doing whatever people do now with > >> beans. Something you didn't mention in your proposal, by the way. > >> > >> I think there's also a fully fleshed out property proposal (including > >> a 'property' keyword) out there somewhere. > >> > >> Possibly make a way to opt out of generating the property change > >> listener support, and just the getters/setters. > >> --Reinier Zwitserloot > >> > >> On Mar 3, 2009, at 15:59, David Goodenough wrote: > >>> Below is my proposal for Lightweight Properties. I know that the > >>> syntax > >>> change is an abbomination to some people, but I have tried to reduce > >>> this to its absolute minimum, while still getting a significant > >>> benefit. > >>> > >>> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 > >>> > >>> AUTHOR(S): > >>> > >>> David Goodenough, long time Java user. I can be reached at > >>> david.goodenough at linkchoose.co.uk. > >>> > >>> OVERVIEW > >>> > >>> FEATURE SUMMARY: > >>> > >>> Lightweight Property support > >>> > >>> MAJOR ADVANTAGE: > >>> > >>> Both BeansBinding (whether JSR-295 or others such an JFace or the > >>> JGoodies > >>> binding) and the JPA Criteria API currently require field names (as > >>> Strings) > >>> as arguments, which an IDE/compiler can not check. With this > >>> proposal the > >>> strings would be abandoned, and the IDE/compiler will be able to > >>> check the > >>> correctness of the code. > >>> > >>> MAJOR BENEFIT: > >>> > >>> Manual checking no longer required. This proposal introduces a > >>> simple well > >>> defined IDE/compiler checkable solution. > >>> > >>> MAJOR DISADVANTAGE: > >>> > >>> It is a language change, and this seems to upset some people. > >>> > >>> ALTERNATIVES: > >>> > >>> None really, apart from using another language or continuing to use > >>> String > >>> names. The existing solutions all require String names which are > >>> uncheckable. > >>> > >>> EXAMPLES > >>> > >>> Lets assume we have a POJO called foo, of type Foo with a field bar > >>> of type > >>> Bar, which itself has a field of type Jim called jim. > >>> > >>> There are two forms of lightweight properties:- > >>> > >>> 1) foo#bar would be translated by the compiler into:- > >>> > >>> new Property(foo,"bar"); > >>> > >>> while foo#bar#jim would be translated into:- > >>> > >>> new Property(foo,"bar","jim"); > >>> > >>> 2) Foo#bar would be translated into:- > >>> > >>> new Property(Foo.class,"bar"); > >>> > >>> while Foo#bar#jim would be translated into:- > >>> > >>> new Property(Foo.class,"bar","jim"); > >>> > >>> These two forms create (1) a bound Property, or (2) an unbound one. > >>> Bound > >>> Properties are explicitly bound to a particular instance of a class > >>> (in this > >>> case foo), while unbound Properties are templates which can be > >>> applied to any > >>> instance of class Foo. Actually bound properties can also be used as > >>> unbound > >>> properties, but that is a harmless and useful side effect not a > >>> primary > >>> intent. > >>> > >>> The Property class would need to be added (it is appended below), > >>> and should > >>> be added either to the java.beans package or to the > >>> java.lang.reflect package > >>> (with which is probably has more in common). > >>> > >>> Syntactically a "#" can be placed wherever a "." can be placed > >>> (except inside > >>> a number), and the same checks need to be made (that each field to > >>> the right > >>> of a # is a field in the left hand side) as would be made for a ".". > >>> The only > >>> difference is in field visibility - For the "#" any field is > >>> visible, which > >>> follows the model currently available in the Field class with > >>> getDeclaredFields(). It also follows the model that while a field > >>> might be > >>> private and therefore not directly accessible from outside, getters > >>> and > >>> setters can provide access. > >>> > >>> The Property object provides type safe access to the field in the > >>> form of > >>> getters and setters. These come in pairs, one for bound and the > >>> other for > >>> unbound access. So for bound access no object is required to fetch > >>> the value, > >>> for an unbound object the parent object needs to be specified. So if > >>> we > >>> have:- > >>> > >>> Propertyprop = foo#bar; > >>> > >>> we can later say:- > >>> > >>> Bar b = prop.get(); > >>> > >>> or for an unbound one from a second Foo object foo2:- > >>> > >>> Bar b = prop.get(foo2); > >>> > >>> The getters and setters in the Property object will defer to > >>> explicitly coded > >>> getters and setters if present, otherwise they will use the Field > >>> getter and > >>> setter. > >>> > >>> If a setter is not explicitly coded, the implicit setter will look > >>> for a > >>> PropertyChangeSupport object in the parent object of the rightmost > >>> field and > >>> fire a PropertyChangeEvent to that object. > >>> > >>> There are also two Annotations provided by the Property class, > >>> ReadOnly and > >>> WriteOnly. These stop implicit getters and setters from trying to > >>> read/write > >>> the property. > >>> > >>> Talking of Annotations, this notation can also be used to get at the > >>> Annotations for a field. So to test for the presence of an > >>> Annotation Ann on > >>> Foo.bar we would use:- > >>> > >>> if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... > >>> > >>> SIMPLE EXAMPLE: > >>> > >>> To take an example from BeansBinding (taken from Shannon Hickey's > >>> blog):- > >>> > >>> // create a BeanProperty representing a bean's firstName > >>> Property firstP = BeanProperty.create("firstName"); > >>> // Bind Duke's first name to the text property of a Swing > >>> JTextField > >>> BeanProperty textP = BeanProperty.create("text"); > >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, > >>> firstP, textfield, textP); > >>> binding.bind(); > >>> > >>> > >>> would instead be written:- > >>> > >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, > >>> duke#firstName, textfield#text); > >>> binding.bind(); > >>> > >>> which of course can be checked by the IDE/compiler, and will not > >>> wait until > >>> run time (not even instantiation time) to show up the error. > >>> > >>> ADVANCED EXAMPLE: > >>> > >>> For a JComboBox (or JList or JTable or JTree) there is a need to map > >>> a list of > >>> objects to the value strings (or column contents). For this we need > >>> to have > >>> an unbound Property which can be applied to each element of the > >>> list. > >>> > >>> Duke duke; > >>> Listdukes; > >>> BoundComboBox combo = new > >>> BoundComboBox(dukes,Duke#fullname,this#duke); > >>> > >>> and now the combo box will be populated from the list dukes, and the > >>> display > >>> values in the list will be taken from the fullname field of each > >>> Duke > >>> element, and the initial value will be set from the local class > >>> field duke > >>> and any changes to the combo box selected element will be reflected > >>> back to > >>> the duke field. > >>> > >>> DETAILS > >>> > >>> SPECIFICATION: > >>> > >>> This proposal adds a new syntactic element, "#", which can be used > >>> in the same > >>> way that "." can be used to qualify fields within a Java object. > >>> > >>> COMPILATION: > >>> > >>> This proposal requires no change to the class files, and is > >>> implemented by a > >>> simple generation of the required instance using the relevant > >>> Property > >>> constructor. Obviously the compiler would have to make sure that the > >>> use that > >>> the property object was being put to (in the examples above the left > >>> hand > >>> side of the assignment) had the correct Generic attributes. > >>> > >>> TESTING: > >>> > >>> How can the feature be tested? > >>> > >>> LIBRARY SUPPORT: > >>> > >>> The new Property class is required (see below). > >>> > >>> REFLECTIVE APIS: > >>> > >>> No changes are required to the reflective APIs although it makes > >>> extensive use > >>> of those APIs. > >>> > >>> OTHER CHANGES: > >>> > >>> No other changes are requires. > >>> > >>> MIGRATION: > >>> > >>> Fortunately there is no code that is formally part of J2SE 6 which > >>> uses such > >>> Properties. There are however two proposals which will need it > >>> (BeansBinding > >>> and JPA Criteria API), but neither of these seem to be destined to > >>> be part of > >>> J2SE 7 (BeansBinding seems to have died the death and the Criteria > >>> API would > >>> be part of the next J2EE which will follow J2SE 7), so this will > >>> provide a > >>> base for them to use and no existing code need to be updated. > >>> > >>> There are other extant Beans-Binding libraries, which could be > >>> modified to use > >>> this proposal, but as none of the existing features have been > >>> changed there > >>> is no need to change them (other than for type safety and compiler/ > >>> IDE > >>> checkability). > >>> > >>> COMPATIBILITY > >>> > >>> BREAKING CHANGES: > >>> > >>> None. This change should not make any existing correct code fail to > >>> compile > >>> or run or change the way in which it compiles/runs. > >>> > >>> EXISTING PROGRAMS: > >>> > >>> No change required to any existing programs > >>> > >>> REFERENCES > >>> > >>> EXISTING BUGS: > >>> > >>> None > >>> > >>> URL FOR PROTOTYPE (optional): > >>> > >>> I do not have the knowledge to make changes to the compiler, and the > >>> only > >>> documentation making such changes concentrated on adding operators > >>> not > >>> changes at this level. So there is no prototype of the compiler > >>> part, but the > >>> Property class follows:- > >>> > >>> package java.lang.reflect; > >>> > >>> import java.beans.BeanInfo; > >>> import java.beans.Introspector; > >>> import java.beans.PropertyChangeSupport; > >>> import java.beans.PropertyDescriptor; > >>> import java.lang.reflect.Field; > >>> import java.lang.reflect.Method; > >>> > >>> /** > >>> * Property class > >>> * This is the support class for use with the # notation to provide > >>> lightweight > >>> * Property support for Java. > >>> * > >>> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd > >>> * @licence LPGL V2 : details of which can be found at http:// > >>> fsf.org. > >>> * @author david.goodenough at linkchoose.co.uk > >>> * > >>> * @param The Parent class for this field > >>> * @param The Type of this field > >>> */ > >>> public class Property { > >>> private C parent; > >>> private Class parentClass; > >>> private Field[] fields; > >>> private PropertyDescriptor[] pd = null; > >>> /** > >>> * Constructor used to create Property objects. The Parent object > >>> may be > >>> * null, but should normally be specified as it can be overridden > >>> anyway. > >>> * @param parent C object that contains the field > >>> * @param field Field describing this field > >>> */ > >>> public Property(C parent, String ... fieldNames) { > >>> this.parent = parent; > >>> this(parent.getClass(), fieldNames); > >>> } > >>> /** > >>> * Constructor for unbound Properties, but also used internally > >>> after > >>> setting > >>> * the parent object by the bound Property objects. > >>> * @param parentClass Class of the parent object > >>> * @param fieldNames String[] of field names > >>> */ > >>> public Property(ClassparentClass, String .. fieldNames) { > >>> this.parentClass = parentClass; > >>> fields = new Field[fieldNames.length]; > >>> pd = new PropertyDescriptor[fieldNames.length]; > >>> outer: for(int index = 0; index < fields.length; index++) { > >>> Field[]dclFields = parentClass.getDeclaredFields(); > >>> for(Field field:dclFields) { > >>> if(field.getName().equals(fieldNames[index])) { > >>> fields[index] = field; > >>> field.setAccessible(true); > >>> try { > >>> BeanInfo beanInfo = > >>> Introspector.getBeanInfo(parent.getClass()); > >>> PropertyDescriptor[]props = > >>> beanInfo.getPropertyDescriptors(); > >>> for(PropertyDescriptor prop : props) { > >>> if(prop.getName().equals(field.getName())) { > >>> pd[index] = prop; > >>> break; > >>> } > >>> } > >>> } catch(Exception e) { /* assume can not find getter/ > >>> setter > >>> */ } > >>> parentClass = field.getType(); > >>> continue outer; > >>> } > >>> } > >>> throw new IllegalArgumentException("Field " + fieldNames[index] + > >>> " not found in class " + > >>> parentClass.getCanonicalName()); > >>> } > >>> } > >>> /** > >>> * Getter from the field in the parent specified when this > >>> Property was > >>> created. > >>> * @see Property.get(C otherParent) > >>> * @return F the value of this field > >>> */ > >>> public F get() { > >>> return get(parent); > >>> } > >>> /** > >>> * Getter with explicit parent. > >>> * This code will check see if this field is WriteOnly, and > >>> complain if it > >>> is. > >>> * It will then see if the use has provided am explicit getter, > >>> and call > >>> that > >>> * if present, otherwise it will just fetch the value through the > >>> Field > >>> provided > >>> * method. > >>> * @param otherParent C parent object > >>> * @return F value of the field > >>> */ > >>> @SuppressWarnings("unchecked") // This should actually not be > >>> needed, > >>> // but the Field.get method is not > >>> typed > >>> public F get(C otherParent) { > >>> Object result = otherParent; > >>> try { > >>> for(int index = 0; index < fields.length; index++) { > >>> > >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > >>> throw new IllegalAccessException( > >>> "Can not get from a WriteOnly field - " + > >>> fields[index].getName()); > >>> Method getter = pd[index] == null ? null : > >>> pd[index].getReadMethod(); > >>> if(getter == null) result = fields[index].get(result); > >>> else result = getter.invoke(result); > >>> } > >>> } catch(Exception e) { > >>> throw new RuntimeException("Should not occur exception", e); > >>> } > >>> return (F)result; > >>> } > >>> /** > >>> * Setter to set the value of the field in the parent object > >>> declared with > >>> the > >>> * Property object > >>> * @param newValue F new value of this field > >>> */ > >>> public void set(F newValue) { > >>> set(parent,newValue); > >>> } > >>> /** > >>> * Setter to set the value of the field to an explicit parent > >>> object. > >>> * If there is a ReadOnly annotation, then we object. If there is > >>> an > >>> explicit > >>> * setter then we use that, otherwise we set the field using the > >>> Field > >>> provided > >>> * set method and if there is a PropertyChangeSupport field, fire a > >>> property > >>> * change event to it. > >>> * We walk our way down the field chain, until we have the last > >>> object and > >>> its > >>> * field, and then we do the set. > >>> * @param parent C explicit parent object > >>> * @param newValue F new value for field in parent > >>> */ > >>> public void set(C parent,F newValue) { > >>> try { > >>> Object last = parent; > >>> int index; > >>> for(index = 0; index < fields.length - 1; index++) { > >>> > >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) > >>> throw new IllegalAccessException( > >>> "Can not get from a WriteOnly field - " + > >>> fields[index].getName()); > >>> Method getter = pd[index] == null ? null : > >>> pd[index].getReadMethod(); > >>> if(getter == null) last = fields[index].get(last); > >>> else last = getter.invoke(last); > >>> } > >>> > >>> if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) > >>> throw new IllegalAccessException( > >>> "Can not get from a WriteOnly field - " + > >>> fields[index].getName()); > >>> Method setter = pd[index] == null ? null : > >>> pd[index].getWriteMethod(); > >>> if(setter == null) { > >>> PropertyChangeSupport pcs = findPcs(last.getClass()); > >>> fields[index].set(last,newValue); > >>> if(pcs != null) > >>> pcs.firePropertyChange(fields[index].getName(), > >>> newValue, > >>> > >>> fields[index].get(last)); > >>> } else setter.invoke(last,newValue); > >>> } catch(Exception e) { > >>> throw new RuntimeException("Should not occur > >>> exception", e); > >>> } > >>> } > >>> /** > >>> * This is used so that the caller can view the Field name > >>> * @return String field name > >>> */ > >>> public String[] getFieldName() { > >>> String[]names = new String[fields.length]; > >>> for(int index = 0; index < fields.length; index++) { > >>> names[index] = fields[index].getName(); > >>> } > >>> return names; > >>> } > >>> /** > >>> * This method is used to fetch the Field array, which is useful > >>> if you > >>> need to > >>> * access the Annotations of a field. > >>> * @return Field[] the array of Fields describing this Property. > >>> */ > >>> public Field[] getFields() { > >>> return fields; > >>> } > >>> /** > >>> * This private method looks for a PropertyChangeSupport object in > >>> the > >>> class and > >>> * if one is found it will return it. It looks right the way up > >>> the class > >>> tree > >>> * by recurring up the superClasses. > >>> * @param parent Class to check for PropertyChangeSupport fields > >>> * @return PropertyChangeSupport first found object, or null if > >>> not found > >>> */ > >>> private PropertyChangeSupport findPcs(Class parent) { > >>> Field fields[] = parent.getDeclaredFields(); > >>> for(Field field:fields) { > >>> field.setAccessible(true); > >>> try { > >>> if(field.getType() == PropertyChangeSupport.class) > >>> return (PropertyChangeSupport)field.get(parent); > >>> } catch(Exception e) { } > >>> } > >>> // If we did not find it then try the superclass > >>> ClasssuperClass = parent.getSuperclass(); > >>> if(superClass == null) return null; > >>> return findPcs(parent.getClass().getSuperclass()); > >>> } > >>> /** > >>> * This annotation is used to mark a field as WriteOnly, i.e. it > >>> can not > >>> be read. > >>> * This stops the automatic getter operation. > >>> */ > >>> public @interface WriteOnly { > >>> } > >>> /** > >>> * This annotation is used to mark a field as ReadOnly, i.e. it > >>> can not be > >>> written. > >>> * This stops the automatic setter operation. > >>> */ > >>> public @interface ReadOnly { > >>> } > >>> } From develop4lasu at gmail.com Tue Mar 3 14:05:26 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Tue, 3 Mar 2009 23:05:26 +0100 Subject: 'This' type In-Reply-To: <16ADB29F-AD69-443D-8C3F-DC25175E6D21@gmx.ch> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <16ADB29F-AD69-443D-8C3F-DC25175E6D21@gmx.ch> Message-ID: <28bca0ff0903031405m6c1c21d0n5359d3eea78a0952@mail.gmail.com> 2009/3/3 Adrian Kuhn > On Mar 3, 2009, at 21:17 , Marek Kozie? wrote: > > ALTERNATIVES: >> Rewriting each method's signature on every class / interface. >> > > Using self-bound generics, such as > > abstract class A> { > abstract Self self(); > } > > class B extends A { > B self(); > } > > class C extends A { > C self(); > } > > This is used in java.lang.Enum for example. > > See also http://www.artima.com/forums/flat.jsp?forum=106&thread=136394 > > --AA Thanks for good sample. Although 'This' could bring relation for generics, or maybe we should think about possibility of defining relations for generics. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From Joe.Darcy at Sun.COM Tue Mar 3 14:21:50 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Tue, 03 Mar 2009 14:21:50 -0800 Subject: 'This' type In-Reply-To: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> Message-ID: <49ADAD7E.4090803@sun.com> Marek Kozie? wrote: > AUTHOR: Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ > > OVERVIEW > > FEATURE SUMMARY: > This type add ability to project valid interfaces(classes) for further > extending/implementing. 'This' means current interface/class type or > something implementing/extending it. > [snip] > DETAILS: > > SPECIFICATION: > (I did not have time to analyze this completely.) > The Project Coin mailing list is not an alternate forum to submit requests for enhancements of the Java specification. Rather, it is a venue for the analysis and refinement of thought-through proposals to change the language. If one is not willing or able to work through implications of the proposal, it it not appropriate to be sent to the list. > REFERENCES > > Notice that considered document does not contain complete analyze of those > solutions and can have some lacks. So if you have some questions/advices > that it does not fully fit with Project Coin, post it on my blog to discuss: > http://lasu2string.blogspot.com/2009/03/this-type.html > Generally the discussion of proposals sent to Project Coin should occur on the Project Coin list. Besides making the current status of proposals easier to track, various parties have expressed interest in why previous language design decisions were made and having all the traffic on Project Coin makes that retrospective analysis possible. -Joe From philvarner at gmail.com Tue Mar 3 14:36:44 2009 From: philvarner at gmail.com (Phil Varner) Date: Tue, 3 Mar 2009 14:36:44 -0800 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: <49ACF691.5090104@paradise.net.nz> References: <49ACF691.5090104@paradise.net.nz> Message-ID: Thanks for the pointer to the bug. One advantage of the syntax "import Sqldate = java.sql.Date;" is that it wouldn't require a keyword addition. It does give a nice "is equivalent to" reading, but also introduces an overloaded meaning for '='. I'm reluctant to include generified types, since, as you say, this should probably be part of a more complete solution. The package alias idea is interesting. I think a more "complete" type aliases proposal is an excellent idea for a separate coin. Were you thinking of something that was included in the type system (as in Haskell) or just a compiler transform? --Phil On Tue, Mar 3, 2009 at 1:21 AM, Bruce Chapman wrote: > My 2 cents: > > This partially covers the need for type aliases, but not for generic > types (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4983159), if > we are going to introduce aliases it should cover the generic case as well. > > An alternative syntax to avoid the 'as' keyword could be > > "import Sqldate = java.sql.Date;" > > Either syntax could probably cover the generic type alias case as well, > however I am not sure if an "import" statement is the right way to do that. > > I liked your examples, some are very compelling. > > An alternative mechanism that preserves the simple names might be to > alias the package rather than aliasing the type. > eg > import ju=java.util; // or import package ju=java.util; > import js=java.sql; > > js.Date date = new js.Date(new ju.Date); > > > That gets further away from solving the generics alias issue, which > might be a good thing : it leaves it easier to do a complete type > aliases solution as a separate issue. ?(IS anyone working on a type > aliases proposal for coin?) > > Bruce > > > Phil Varner wrote: >> Import Aliases for Classes and Static Methods >> >> http://docs.google.com/Doc?id=dgx74dt7_19dxnspbhj >> >> AUTHOR: Phil Varner >> >> OVERVIEW >> >> FEATURE SUMMARY: The import aliases feature allows a user to provide >> an alias underwhich an imported class or statically imported method >> must be referred to in the containing source file. ? An example of the >> use of this feature is "import java.sql.Date as SqlDate;" >> >> MAJOR ADVANTAGE: This feature would allow easier use of multiple >> classes which have the same name but different packages to be used in >> the same source file. >> >> MAJOR BENEFIT: This will prevent the necessity of fully-qualifiying >> all class references when there is a name collision, leading to more >> readable code. >> >> MAJOR DISADVANTAGE: ?This will introduce an extra level of indirection >> when determing the source of a given class or method, introduce a new >> keyword 'as', and will require changes to IDE code completion >> functionality. >> >> ALTERNATIVES: In some cases, a nested class can be created which >> trivially derives a class involved in the name collision. ?For a >> method, a wrapper method can be created in the source file. >> >> EXAMPLES >> >> SIMPLE EXAMPLE: >> >> Example #1, duplicate class name >> >> Current code: >> >> new java.sql.Date(new java.util.Date()); >> >> New code: >> >> import java.sql.Date as SqlDate; >> import java.util.Date as UtilDate; >> >> new SqlDate(new UtilDate()); >> >> Example #2, statically imported method alias >> >> Current code: >> >> import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName; >> >> public static int mrlacsmn(final int arg1, final String arg2){ >> ? ? return myReallyLongAndComplicatedStaticMethodName(arg1, arg2); >> } >> >> mrlacsmn(1, a); >> >> New code: >> >> import static com.philvarner.some.pkg.myReallyLongAndComplicatedStaticMethodName >> as mrlacsmn; >> >> mrlacsmn(1, a); >> >> ADVANCED EXAMPLE: >> >> Example #3 >> >> Translation of persistent formats between similar APIs. >> >> In many domains, it is not uncommon to have two different APIs with >> classes with the same name. ?For example, in a production rules API, >> one may have classes "RuleSet" and "Rule". ?When attempting to use the >> API to translate between these these APIs, it must be decided that one >> is fully-qualified and one is not. ?This can lead to code like: >> >> com.example.foo.bar.sdk.RuleSet srcRuleSet = ...; >> com.example.foo.bar.sdk2.RuleSet dstRuleSet = new >> com.example.foo.bar.sdk2.RuleSet(); >> migrate(srcRuleSet, dstRuleSet); >> ... >> >> private static void migrate(com.example.foo.bar.sdk.RuleSet srcRuleSet, >> ? ? ? ? ? ? ? ? ? ? ? ? com.example.foo.bar.sdk2.RuleSet dstRuleSet){ >> ... >> } >> >> Note that it is good practice here not to import either class because >> it is too easy to accidentally misuse constants and static methods. >> >> With the 'as' syntax, one could instead write the far less verbose and >> more readible: >> >> import com.example.foo.bar.sdk.RuleSet as SrcRuleSet; >> import com.example.foo.bar.sdk2.RuleSet as DstRuleSet; >> >> ... >> >> SrcRuleSet srcRuleSet = ...; >> DstRuleSet destRuleSet = new DstRuleSet(); >> migrate(srcRuleSet, dstRuleSet); >> >> ... >> >> private static void migrate(SrcRuleSet srcRuleSet, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? DstRuleSet dstRuleSet){ >> ... >> } >> >> Example #4 >> >> Ensuring correct method selection when static importing overloaded methods. >> >> Current code: >> import static org.testng.Assert.assertEquals; >> >> public static int aeo(Object arg1, Object arg2){ >> ? ? assertEquals(arg1, arg2); >> } >> >> public static int aec(Collection arg1, Collection arg2){ >> ? ? assertEquals(arg1, arg2); >> } >> >> aeo(obj1, obj2); >> aec(list1, list2); >> >> New code: >> >> import static org.testng.Assert.assertEquals(Object, Object) as aeo; >> import static org.testng.Assert.assertEquals(Collection, Collection) as aec; >> >> aeo(obj1, obj2); >> aec(list1, list2); >> >> Note: it is possible that this sort of method selection is beyond the >> scope of a COIN proposal >> >> DETAILS >> >> SPECIFICATION: >> >> Grammar >> >> modification (JLS 3.9): >> Keyword: >> ? ? as >> ? ? ... >> >> modification (JLS 7.5): >> ImportDeclaration: >> ? ? SingleTypeImportDeclarationWithAlias >> ? ? SingleStaticImportDeclarationWithAlias >> ? ? ... >> >> addition: >> SingleTypeImportDeclarationWithAlias: >> ? ? import TypeName as Identifier; >> >> addition: >> SingleStaticImportDeclarationWithAlias: >> ? ? import static TypeName . Identifier as Identifier; >> >> >> Note that this would explicitly forbid wildcard imports from being aliased. >> >> There are no known effects on the type system or meaning of >> expressions and statements in the Java Programming Language. >> >> COMPILATION: This feature would be a compile-time transform. ?It would >> only affect the way in which a non-fully qualified class or method >> name was resolved to a fully-qualified class or method name. >> >> TESTING: This change would be tested in a manner similar how how the >> existing code which resolves the fully-qualified names of classes and >> methods is tested. >> >> LIBRARY SUPPORT: No change >> >> REFLECTIVE APIS: No change >> >> OTHER CHANGES: No change >> >> MIGRATION: This change is backwards-compatible with existing code. >> >> COMPATIBILITY >> >> BREAKING CHANGES: No change >> >> EXISTING PROGRAMS: No change >> >> REFERENCES >> >> EXISTING BUGS: None at present >> >> URL FOR PROTOTYPE (optional): None at present >> >> > > > > -- Machines might be interesting, but people are fascinating. -- K.P. From cadenza at paradise.net.nz Tue Mar 3 13:07:17 2009 From: cadenza at paradise.net.nz (cadenza at paradise.net.nz) Date: Wed, 04 Mar 2009 10:07:17 +1300 (NZDT) Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <49AD1B58.5060305@joda.org> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> <49AD1B58.5060305@joda.org> Message-ID: <1236114437.49ad9c05d493c@www.paradise.net.nz> > This will be very confusing when you use Foo from another part of your > application and expect the value to be non-null and get a NPE. In fact > the @Nonnull is positvely misleading. > > Basically, you can't rely on JSR-305. The information needs to be > rechecked. Thus, whats the point in using it at all?!! Documentation > perhaps? Annotations are not suitable for handling language level issues > > like nulls. An annotation processor visible to javac could perform the @nonNull check and cause the compilation to fail. JSR-305 defines a standard set of annotations with precise defined meaning so that tools don't need to define their own, and so you don't need to change your code when you change the tooling. That has great value. With the annotations standardised the tooling will follow, no doubt some will be implemented as though they are part of javac, and some will not. Bruce Quoting Stephen Colebourne : > Jeremy Manson wrote: > >> The principle perceived disadvantage, however, is that it > encourages, > >> rather than discourages, the use of null values in APIs. > > > > I would think that the principle disadvantage would be not that it > > encourages use of null values (which, as you point out, is fine in > > some contexts), but that it encourages programmers not to think about > > what happens when there is a null value. > > But that is exactly what already happens today. Most developers are very > > poor at thinking through the null consequences of a method - the happy > day scenario is the one focussed on. > > > I can easily imagine > > programmers using this all of the time without thinking about it, and > > then being surprised when a null ends up in the wrong place and not > > knowing how it got there. Even with a simple example: > > > > public String someFunction(String a, String b) { > > String s = a?.concat("foo"); > > String t = b?.concat(a); > > return myHashMap?.get(t); > > } > > > > Now, someFunction returns null. Is it because a was null? Or b was > > null? Or myHashMap was null? Or there was no mapping for t in > > myHashMap? > > Or perhaps it doesn't matter, and thats why the code was written that > way. Null as 'don't know' or 'don't care' is incredibly common. > > > If you want to cut down on > > extraneous if-testing, I would use JSR-305's Nullity annotations > > instead. > > What does this code do when passed null? > > Foo f = new Foo(null); > int v = f.value; > > public class Foo { > public final Integer value; > public Foo(@Nonnull Integer value) { > this.value = value; > } > } > > There is a NPE at f.value, not at new Foo(null). > > You would think that you could never construct an instance of Foo with a > > val of null, but you can. The @Nonnull annotation doesn't have any real > > meaning unless it is checked using a tool, and javac isn't such a tool. > > This will be very confusing when you use Foo from another part of your > application and expect the value to be non-null and get a NPE. In fact > the @Nonnull is positvely misleading. > > Basically, you can't rely on JSR-305. The information needs to be > rechecked. Thus, whats the point in using it at all?!! Documentation > perhaps? Annotations are not suitable for handling language level issues > > like nulls. > > Stephen > > From thorsten at vanellen.de Tue Mar 3 13:18:54 2009 From: thorsten at vanellen.de (Thorsten van Ellen) Date: Tue, 03 Mar 2009 22:18:54 +0100 Subject: Automatic Resource Management and Simple Resource Clean-up Message-ID: <49AD9EBE.5010808@vanellen.de> Josh, Neal and Roger! I have had this idea also for a long time. I think it is in a "tradition" of java of suppressing typical programming errors. A good example for the tradition is automatic memory management and garbage collection that is a very complex mechanism to avoid one very typical programming error. Management of resources other than memory usually is really as buggy as memory management. My observation is that resource management is one of the most frequent bug pattern I know of. Look at any project: you hardly find correct optimal implemented examples and you nearly always find bugs in every non trivial project. Analysing/finding the bug often is very difficult like finding memory management bugs. It seems to me, the feature benefit is worth some more effort. The effort of thinking a bit more about it might be not too much, especially if your heading toward a "minimal" solution like "simple clean up", but I don't know what is "affordable" in jdk7-schedule. Just to put in some additional/new ideas and to "make the cake bigger" before it is reduced to the optimal solution ("brain-storming", sometimes thinkind around a corner helps): Both proposed solutions might have problems with resource management, that is distributed/shared/spread between two or more separated methods. Such problems might be solved with a kind of GOF-"pattern", interfaces and a tiny "resource management library". And there exist even more complicated resource management problems like ACID database transactions that do not only have one "close"-operation but two (commit and rollback) and a more complex decision process between those. But regarding these additional ideas may also be counterproductive for a tiny language modification that solves 98 % of the typical bugs and therefore may also be ignored! Best regards Thorsten van Ellen From akuhn at gmx.ch Tue Mar 3 13:51:11 2009 From: akuhn at gmx.ch (Adrian Kuhn) Date: Tue, 3 Mar 2009 22:51:11 +0100 Subject: 'This' type In-Reply-To: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> Message-ID: <16ADB29F-AD69-443D-8C3F-DC25175E6D21@gmx.ch> On Mar 3, 2009, at 21:17 , Marek Kozie? wrote: > ALTERNATIVES: > Rewriting each method's signature on every class / interface. Using self-bound generics, such as abstract class A> { abstract Self self(); } class B extends A { B self(); } class C extends A { C self(); } This is used in java.lang.Enum for example. See also http://www.artima.com/forums/flat.jsp?forum=106&thread=136394 --AA From Joe.Darcy at Sun.COM Tue Mar 3 17:29:28 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Tue, 03 Mar 2009 17:29:28 -0800 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <29B06FDC-80AB-46E0-AABB-C97F9F9AF405@zwitserloot.com> <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> Message-ID: <49ADD978.3080804@sun.com> Neal Gafter wrote: > Joe Darcy sort of ruled out adding property support in project coin in > http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size > Correct; properties (and closures and reified generics) are examples of changes out of scope for Project Coin. -Joe > Regards, > Neal > > On Tue, Mar 3, 2009 at 12:05 PM, Reinier Zwitserloot > wrote: > >> You call that lightweight? >> >> How about following the beans spec more to the letter and just >> generate the addPropertyChangeListener, removePropertyChangeListener, >> setX(), and get/isX() method in response to seeing a keyword or >> annotation on a given field. You'll have to work out the details, but >> that sounds far, far simpler to understand. >> >> You'll need to flesh this out, but it would look something like: >> >> public class Foo { >> private property int x; >> } >> >> Which would generate the addPropertyChangeListener, >> removePropertyChangeListener, setX, getX methods, all public, along >> with the required infrastructure to make it tick. If you don't like >> the generation, for example because you want the setter to be package >> private, you just add the setter in the source file; the keyword will >> only generate the missing stuff. It doesn't cover every use case, but >> there's always the alternative of doing whatever people do now with >> beans. Something you didn't mention in your proposal, by the way. >> >> I think there's also a fully fleshed out property proposal (including >> a 'property' keyword) out there somewhere. >> >> Possibly make a way to opt out of generating the property change >> listener support, and just the getters/setters. >> --Reinier Zwitserloot >> >> >> >> On Mar 3, 2009, at 15:59, David Goodenough wrote: >> >> >>> Below is my proposal for Lightweight Properties. I know that the >>> syntax >>> change is an abbomination to some people, but I have tried to reduce >>> this to its absolute minimum, while still getting a significant >>> benefit. >>> >>> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 >>> >>> AUTHOR(S): >>> >>> David Goodenough, long time Java user. I can be reached at >>> david.goodenough at linkchoose.co.uk. >>> >>> OVERVIEW >>> >>> FEATURE SUMMARY: >>> >>> Lightweight Property support >>> >>> MAJOR ADVANTAGE: >>> >>> Both BeansBinding (whether JSR-295 or others such an JFace or the >>> JGoodies >>> binding) and the JPA Criteria API currently require field names (as >>> Strings) >>> as arguments, which an IDE/compiler can not check. With this >>> proposal the >>> strings would be abandoned, and the IDE/compiler will be able to >>> check the >>> correctness of the code. >>> >>> MAJOR BENEFIT: >>> >>> Manual checking no longer required. This proposal introduces a >>> simple well >>> defined IDE/compiler checkable solution. >>> >>> MAJOR DISADVANTAGE: >>> >>> It is a language change, and this seems to upset some people. >>> >>> ALTERNATIVES: >>> >>> None really, apart from using another language or continuing to use >>> String >>> names. The existing solutions all require String names which are >>> uncheckable. >>> >>> EXAMPLES >>> >>> Lets assume we have a POJO called foo, of type Foo with a field bar >>> of type >>> Bar, which itself has a field of type Jim called jim. >>> >>> There are two forms of lightweight properties:- >>> >>> 1) foo#bar would be translated by the compiler into:- >>> >>> new Property(foo,"bar"); >>> >>> while foo#bar#jim would be translated into:- >>> >>> new Property(foo,"bar","jim"); >>> >>> 2) Foo#bar would be translated into:- >>> >>> new Property(Foo.class,"bar"); >>> >>> while Foo#bar#jim would be translated into:- >>> >>> new Property(Foo.class,"bar","jim"); >>> >>> These two forms create (1) a bound Property, or (2) an unbound one. >>> Bound >>> Properties are explicitly bound to a particular instance of a class >>> (in this >>> case foo), while unbound Properties are templates which can be >>> applied to any >>> instance of class Foo. Actually bound properties can also be used as >>> unbound >>> properties, but that is a harmless and useful side effect not a >>> primary >>> intent. >>> >>> The Property class would need to be added (it is appended below), >>> and should >>> be added either to the java.beans package or to the >>> java.lang.reflect package >>> (with which is probably has more in common). >>> >>> Syntactically a "#" can be placed wherever a "." can be placed >>> (except inside >>> a number), and the same checks need to be made (that each field to >>> the right >>> of a # is a field in the left hand side) as would be made for a ".". >>> The only >>> difference is in field visibility - For the "#" any field is >>> visible, which >>> follows the model currently available in the Field class with >>> getDeclaredFields(). It also follows the model that while a field >>> might be >>> private and therefore not directly accessible from outside, getters >>> and >>> setters can provide access. >>> >>> The Property object provides type safe access to the field in the >>> form of >>> getters and setters. These come in pairs, one for bound and the >>> other for >>> unbound access. So for bound access no object is required to fetch >>> the value, >>> for an unbound object the parent object needs to be specified. So if >>> we >>> have:- >>> >>> Propertyprop = foo#bar; >>> >>> we can later say:- >>> >>> Bar b = prop.get(); >>> >>> or for an unbound one from a second Foo object foo2:- >>> >>> Bar b = prop.get(foo2); >>> >>> The getters and setters in the Property object will defer to >>> explicitly coded >>> getters and setters if present, otherwise they will use the Field >>> getter and >>> setter. >>> >>> If a setter is not explicitly coded, the implicit setter will look >>> for a >>> PropertyChangeSupport object in the parent object of the rightmost >>> field and >>> fire a PropertyChangeEvent to that object. >>> >>> There are also two Annotations provided by the Property class, >>> ReadOnly and >>> WriteOnly. These stop implicit getters and setters from trying to >>> read/write >>> the property. >>> >>> Talking of Annotations, this notation can also be used to get at the >>> Annotations for a field. So to test for the presence of an >>> Annotation Ann on >>> Foo.bar we would use:- >>> >>> if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ... >>> >>> SIMPLE EXAMPLE: >>> >>> To take an example from BeansBinding (taken from Shannon Hickey's >>> blog):- >>> >>> // create a BeanProperty representing a bean's firstName >>> Property firstP = BeanProperty.create("firstName"); >>> // Bind Duke's first name to the text property of a Swing JTextField >>> BeanProperty textP = BeanProperty.create("text"); >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, duke, >>> firstP, textfield, textP); >>> binding.bind(); >>> >>> >>> would instead be written:- >>> >>> Binding binding = Bindings.createAutoBinding(READ_WRITE, >>> duke#firstName, textfield#text); >>> binding.bind(); >>> >>> which of course can be checked by the IDE/compiler, and will not >>> wait until >>> run time (not even instantiation time) to show up the error. >>> >>> ADVANCED EXAMPLE: >>> >>> For a JComboBox (or JList or JTable or JTree) there is a need to map >>> a list of >>> objects to the value strings (or column contents). For this we need >>> to have >>> an unbound Property which can be applied to each element of the list. >>> >>> Duke duke; >>> Listdukes; >>> BoundComboBox combo = new >>> BoundComboBox(dukes,Duke#fullname,this#duke); >>> >>> and now the combo box will be populated from the list dukes, and the >>> display >>> values in the list will be taken from the fullname field of each Duke >>> element, and the initial value will be set from the local class >>> field duke >>> and any changes to the combo box selected element will be reflected >>> back to >>> the duke field. >>> >>> DETAILS >>> >>> SPECIFICATION: >>> >>> This proposal adds a new syntactic element, "#", which can be used >>> in the same >>> way that "." can be used to qualify fields within a Java object. >>> >>> COMPILATION: >>> >>> This proposal requires no change to the class files, and is >>> implemented by a >>> simple generation of the required instance using the relevant Property >>> constructor. Obviously the compiler would have to make sure that the >>> use that >>> the property object was being put to (in the examples above the left >>> hand >>> side of the assignment) had the correct Generic attributes. >>> >>> TESTING: >>> >>> How can the feature be tested? >>> >>> LIBRARY SUPPORT: >>> >>> The new Property class is required (see below). >>> >>> REFLECTIVE APIS: >>> >>> No changes are required to the reflective APIs although it makes >>> extensive use >>> of those APIs. >>> >>> OTHER CHANGES: >>> >>> No other changes are requires. >>> >>> MIGRATION: >>> >>> Fortunately there is no code that is formally part of J2SE 6 which >>> uses such >>> Properties. There are however two proposals which will need it >>> (BeansBinding >>> and JPA Criteria API), but neither of these seem to be destined to >>> be part of >>> J2SE 7 (BeansBinding seems to have died the death and the Criteria >>> API would >>> be part of the next J2EE which will follow J2SE 7), so this will >>> provide a >>> base for them to use and no existing code need to be updated. >>> >>> There are other extant Beans-Binding libraries, which could be >>> modified to use >>> this proposal, but as none of the existing features have been >>> changed there >>> is no need to change them (other than for type safety and compiler/IDE >>> checkability). >>> >>> COMPATIBILITY >>> >>> BREAKING CHANGES: >>> >>> None. This change should not make any existing correct code fail to >>> compile >>> or run or change the way in which it compiles/runs. >>> >>> EXISTING PROGRAMS: >>> >>> No change required to any existing programs >>> >>> REFERENCES >>> >>> EXISTING BUGS: >>> >>> None >>> >>> URL FOR PROTOTYPE (optional): >>> >>> I do not have the knowledge to make changes to the compiler, and the >>> only >>> documentation making such changes concentrated on adding operators not >>> changes at this level. So there is no prototype of the compiler >>> part, but the >>> Property class follows:- >>> >>> package java.lang.reflect; >>> >>> import java.beans.BeanInfo; >>> import java.beans.Introspector; >>> import java.beans.PropertyChangeSupport; >>> import java.beans.PropertyDescriptor; >>> import java.lang.reflect.Field; >>> import java.lang.reflect.Method; >>> >>> /** >>> * Property class >>> * This is the support class for use with the # notation to provide >>> lightweight >>> * Property support for Java. >>> * >>> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd >>> * @licence LPGL V2 : details of which can be found at http://fsf.org. >>> * @author david.goodenough at linkchoose.co.uk >>> * >>> * @param The Parent class for this field >>> * @param The Type of this field >>> */ >>> public class Property { >>> private C parent; >>> private Class parentClass; >>> private Field[] fields; >>> private PropertyDescriptor[] pd = null; >>> /** >>> * Constructor used to create Property objects. The Parent object >>> may be >>> * null, but should normally be specified as it can be overridden >>> anyway. >>> * @param parent C object that contains the field >>> * @param field Field describing this field >>> */ >>> public Property(C parent, String ... fieldNames) { >>> this.parent = parent; >>> this(parent.getClass(), fieldNames); >>> } >>> /** >>> * Constructor for unbound Properties, but also used internally >>> after >>> setting >>> * the parent object by the bound Property objects. >>> * @param parentClass Class of the parent object >>> * @param fieldNames String[] of field names >>> */ >>> public Property(ClassparentClass, String .. fieldNames) { >>> this.parentClass = parentClass; >>> fields = new Field[fieldNames.length]; >>> pd = new PropertyDescriptor[fieldNames.length]; >>> outer: for(int index = 0; index < fields.length; index++) { >>> Field[]dclFields = parentClass.getDeclaredFields(); >>> for(Field field:dclFields) { >>> if(field.getName().equals(fieldNames[index])) { >>> fields[index] = field; >>> field.setAccessible(true); >>> try { >>> BeanInfo beanInfo = >>> Introspector.getBeanInfo(parent.getClass()); >>> PropertyDescriptor[]props = >>> beanInfo.getPropertyDescriptors(); >>> for(PropertyDescriptor prop : props) { >>> if(prop.getName().equals(field.getName())) { >>> pd[index] = prop; >>> break; >>> } >>> } >>> } catch(Exception e) { /* assume can not find getter/ >>> setter >>> */ } >>> parentClass = field.getType(); >>> continue outer; >>> } >>> } >>> throw new IllegalArgumentException("Field " + fieldNames[index] + >>> " not found in class " + >>> parentClass.getCanonicalName()); >>> } >>> } >>> /** >>> * Getter from the field in the parent specified when this >>> Property was >>> created. >>> * @see Property.get(C otherParent) >>> * @return F the value of this field >>> */ >>> public F get() { >>> return get(parent); >>> } >>> /** >>> * Getter with explicit parent. >>> * This code will check see if this field is WriteOnly, and >>> complain if it >>> is. >>> * It will then see if the use has provided am explicit getter, >>> and call >>> that >>> * if present, otherwise it will just fetch the value through the >>> Field >>> provided >>> * method. >>> * @param otherParent C parent object >>> * @return F value of the field >>> */ >>> @SuppressWarnings("unchecked") // This should actually not be >>> needed, >>> // but the Field.get method is not >>> typed >>> public F get(C otherParent) { >>> Object result = otherParent; >>> try { >>> for(int index = 0; index < fields.length; index++) { >>> >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method getter = pd[index] == null ? null : >>> pd[index].getReadMethod(); >>> if(getter == null) result = fields[index].get(result); >>> else result = getter.invoke(result); >>> } >>> } catch(Exception e) { >>> throw new RuntimeException("Should not occur exception", e); >>> } >>> return (F)result; >>> } >>> /** >>> * Setter to set the value of the field in the parent object >>> declared with >>> the >>> * Property object >>> * @param newValue F new value of this field >>> */ >>> public void set(F newValue) { >>> set(parent,newValue); >>> } >>> /** >>> * Setter to set the value of the field to an explicit parent >>> object. >>> * If there is a ReadOnly annotation, then we object. If there is >>> an >>> explicit >>> * setter then we use that, otherwise we set the field using the >>> Field >>> provided >>> * set method and if there is a PropertyChangeSupport field, fire a >>> property >>> * change event to it. >>> * We walk our way down the field chain, until we have the last >>> object and >>> its >>> * field, and then we do the set. >>> * @param parent C explicit parent object >>> * @param newValue F new value for field in parent >>> */ >>> public void set(C parent,F newValue) { >>> try { >>> Object last = parent; >>> int index; >>> for(index = 0; index < fields.length - 1; index++) { >>> >>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method getter = pd[index] == null ? null : >>> pd[index].getReadMethod(); >>> if(getter == null) last = fields[index].get(last); >>> else last = getter.invoke(last); >>> } >>> >>> if(fields[index].getType().isAnnotationPresent(ReadOnly.class)) >>> throw new IllegalAccessException( >>> "Can not get from a WriteOnly field - " + >>> fields[index].getName()); >>> Method setter = pd[index] == null ? null : >>> pd[index].getWriteMethod(); >>> if(setter == null) { >>> PropertyChangeSupport pcs = findPcs(last.getClass()); >>> fields[index].set(last,newValue); >>> if(pcs != null) >>> pcs.firePropertyChange(fields[index].getName(), >>> newValue, >>> >>> fields[index].get(last)); >>> } else setter.invoke(last,newValue); >>> } catch(Exception e) { >>> throw new RuntimeException("Should not occur >>> exception", e); >>> } >>> } >>> /** >>> * This is used so that the caller can view the Field name >>> * @return String field name >>> */ >>> public String[] getFieldName() { >>> String[]names = new String[fields.length]; >>> for(int index = 0; index < fields.length; index++) { >>> names[index] = fields[index].getName(); >>> } >>> return names; >>> } >>> /** >>> * This method is used to fetch the Field array, which is useful >>> if you >>> need to >>> * access the Annotations of a field. >>> * @return Field[] the array of Fields describing this Property. >>> */ >>> public Field[] getFields() { >>> return fields; >>> } >>> /** >>> * This private method looks for a PropertyChangeSupport object in >>> the >>> class and >>> * if one is found it will return it. It looks right the way up >>> the class >>> tree >>> * by recurring up the superClasses. >>> * @param parent Class to check for PropertyChangeSupport fields >>> * @return PropertyChangeSupport first found object, or null if >>> not found >>> */ >>> private PropertyChangeSupport findPcs(Class parent) { >>> Field fields[] = parent.getDeclaredFields(); >>> for(Field field:fields) { >>> field.setAccessible(true); >>> try { >>> if(field.getType() == PropertyChangeSupport.class) >>> return (PropertyChangeSupport)field.get(parent); >>> } catch(Exception e) { } >>> } >>> // If we did not find it then try the superclass >>> ClasssuperClass = parent.getSuperclass(); >>> if(superClass == null) return null; >>> return findPcs(parent.getClass().getSuperclass()); >>> } >>> /** >>> * This annotation is used to mark a field as WriteOnly, i.e. it >>> can not >>> be read. >>> * This stops the automatic getter operation. >>> */ >>> public @interface WriteOnly { >>> } >>> /** >>> * This annotation is used to mark a field as ReadOnly, i.e. it >>> can not be >>> written. >>> * This stops the automatic setter operation. >>> */ >>> public @interface ReadOnly { >>> } >>> } >>> >>> >> >> > > From reinier at zwitserloot.com Tue Mar 3 16:09:40 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 4 Mar 2009 01:09:40 +0100 Subject: PROPOSAL: Static Methods in Interfaces Message-ID: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> Apparently the previous version's attachment didn't come through properly, so here's an inline HTML version. Static Methods in Interfaces VERSION This is version 1.0. The latest version can be found at http://tinyurl.com/static-methods-in-interfaces AUTHOR(S): Reinier Zwitserloot Roel Spilker OVERVIEW FEATURE SUMMARY: Static methods are now allowed in interfaces. The static method is defined with a method body in the interface and it exists in the namespace of the interface; it does not imply that implementing classes must implement the method. This feature is especially useful for utility methods that belong with a given interface. For example, many methods in java.util.Collections are specific for a particular interface, such as sort (java.util.List) and unmodifiableMap (java.util.Map). MAJOR ADVANTAGE: Allows maintaining code that 'goes together' in a single file, and helps auto-complete dialogs come up with more relevant operations on any given object. Also improves syntax by using a more specific term (e.g. List) instead of a usually somewhat generic grab bag utility class (e.g. Collections). Also allows interfaces to contain pseudo- constructor, for common tasks and default implementations (e.g. java.io.FileFilter could contain a method to create a new one based on a file extension). This proposal will also offer an easy solution to the current deplorable situation that you need to call on 2 separate utility classes, one of which has no relation to List whatsoever, just to create an immutable List: Collections.unmodifiableList(Arrays.asList(items)) can be replaced with the much more elegant List.of(items) MAJOR BENEFIT: Java (the language) is very strictly namespaced; the default package is discouraged and java does not allow dynamically adding or changing methods at runtime (so called monkey patching). Java also does not support mixins nor multiple inheritance. Therefore, the platform currently lacks a way to meaningfully offer utility methods for interfaces. Instead, kludges such as java.util.Collections exist as a vehicle for these support methods. Furthermore, static methods in interfaces are currently illegal (see JLS Chapter 9.4) so this proposed change does not complicate the language very much. MAJOR DISADVANTAGE: Confusion about the notion that static methods in java in java are not 'virtual' (they are not inherited and cannot be overridden) may cause a programmer to erroneously think a static method in an interface implies it is something an implementing class must implement. However, the mandatory method body should help avoid confusion. Slightly more complex language specification. No opportunity to use the static keyword in interfaces for some sort of factory interface concept (an interface for constructors and static methods). The proposed implementation is also somewhat inconsistent in rare cases compared to static methods in classes. While this inconsistency is a disadvantage, the authors do not believe there's a way to avoid this inconsistency without creating more serious disadvantages ALTERNATIVES: The usual solution to this problem right now is to offer a separate utility class (a class that is not instantiable and contains only static methods) that contain the utility methods, along with a reference in the javadoc of the interface to this utility class. For example, java.util.Collections is the utility class that goes with Map, List, Set and other Java Collections API interfaces. The use case of default / common implementations is currently handled by having an implementing class with a constructor. For example, a new class called java.io.ExtensionFileFilter could be made that takes a String and implements FileFilter. The sugar employed by this proposal is itself also an alternative: Creating a member type class that contains the static methods (With just a backwards and migration compatible API addition, you could make List.Utils.of(items) work in java 1.6 notation (The Utils class is an inner member type to the interface, which is legal, and as it is a class, may contain static methods. EXAMPLES SIMPLE EXAMPLE: public interface Foo { public static void printHello() { System.out.println("Hello, World!"); } } Foo.printHello(); //Prints 'Hello, World! ADVANCED EXAMPLE: package java.util; public interface List extends Collection { int size(); // List's other instance methods public static List of(final T... items) { return new AbstractList() { public T get(int index) { return items[index]; } public int size() { return items.length; } }; } } List list = List.of("foo", "bar"); assert list.get(0).equals("foo"); assert list.size() == 2; DETAILS SPECIFICATION: Java Language Specification changes: JLS Chapter 9.1.4: original: InterfaceMemberDeclaration: ConstantDeclaration AbstractMethodDeclaration ClassDeclaration InterfaceDeclaration ; replacement: InterfaceMemberDeclaration: ConstantDeclaration AbstractMethodDeclaration StaticMethodDeclaration ClassDeclaration InterfaceDeclaration ; JLS Chapter 9.4: original: Every method declaration in the body of an interface is implicitly abstract, so its body is always represented by a semicolon, not a block. replacement: Every non-static method declaration in the body of an interface is implicitly abstract, so its body is always represented by a semicolon, not a block. original: Note that a method declarated in an interface must not be declared static, or a compile-time error occurs, because static methods cannot be abstract. replacement: None - this line is removed from the JLS. JLS Chapter 9.5 and 9.6 are bumped to 9.6 and 9.7, respectively, and a new 9.5 is added: 9.5 Static Method Declarations StaticMethodDeclaration: StaticMethodModifiers TypeParametersopt ResultType MethodDeclarator Throwsopt ; StaticMethodModifiers: static MethodModifiers static static MethodModifiers The MethodModifiers are described in ?8.4.3, The access modifier public is discussed in ?6.6. A compile-time error occurs if the same modifier appears more than once in an static method declaration. The static keyword is mandatory. Static method declarations in interfaces are either public or private; protected and package private are not allowed. If no access modifier is specified, the static method is implicitly public, to be consistent with the notion that everything else in an interface, be it a field, an abstract method, or a member type, is implicitly public. Private static methods are allowed to accommodate helper methods. Other than being limited to public and private access, a static interface method is identical to a method declaration in a class (?8.4). During compilation, all static methods are stored in a synthetic inner class called $Methods, which is generated with a private constructor. If that class already exists in the source file, a compile-time error occurs. JLS Chapter 15.12.1: The specification of method invocation forms that invoke static methods are updated to refer to 'class or interface' instead of just 'class', and the following line: If TypeName is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only static methods and interfaces have no static methods. is replaced with: If TypeName is the name of an interface rather than a class, then the call is presumed to be for a static method in a synthetic member class of the interface, called $Methods. If the method exists, the class to be searched is denoted by TypeName.$Methods where $Methods is a static inner class of the interface TypeName, literally called "$Methods". COMPILATION: Any interface with static methods is sugared by creating a member class called $Methods which will contain the static methods. The generated $Methods class should also have a private constructor, as they aren't supposed to be instantiable. If the $Methods inner class has been explicitly created in the source file, any static methods in the interface are considered a compile-time error (if the class is present in the source file, the assumption is that the programmer wants to keep manual control of the static methods). For method invocations, currently, an invocation of the form InterfaceName.method(), will result in an immediate compile error. The compiler will instead need to search the $Methods class (if any exists) for the method, and rewrite the call toInterfaceName. $Methods.method() if the method does exist in the $Methods inner class. The method is not inherited by any member types. So, the second 'hello()' call in the following example would result in a compile time error (method not found): public interface Foo { public static void hello() { System.out.println("Hello, World!"); } } public class Bar implements Foo {} Foo.hello(); //works Bar.hello(); //does not work This is an unfortunate inconsistency (if Foo was a class, Bar.hello() would work just fine), but there is no way to adequately recreate this inheritance system with syntax sugar. Even with a more thorough solution (that involves changing the JVM), allowing inheritance of the methods would mean allowing diamond relations (where 1 class implements 2 interfaces, that each have the same static method signature with different implementations. Which one is chosen?). This is principally the reason why this proposal suggests not letting the method be inherited. However, if inheritance is deemed important, the alternate solution is to fix the JVM Specification chapter 2.13 in similar ways as the JLS, and make static methods legal in interfaces. The Type.method() invocation would then require a much broader search and should give up with a compile-time error if a diamond relation is found, listing the conflicting implementations and asking the programmer to choose one. As this proposal breaks the norm on inheritance already, the following syntax is not allowed either, which for static methods in classes is currently legal but flagged as a warning in all popular IDEs and code style checkers: Character c = 'f'; c.isWhiteSpace(' '); //if Character was an interface, this would not be legal. TESTING: This new feature can be tested by applying the existing tests for static method calls to static methods in interfaces. Compilation and class file parsing needs to be expanded to apply tests to read method bodies in interfaces as well as classes. "Finding" the static method inside the $Methods inner class during compilation needs to be tested, which is straight forward. The changes described below to the reflective APIs also need testing, which is also straight forward. LIBRARY SUPPORT: No library support is needed. However, it would be advisable to update various interfaces in the core java APIs with useful static utility methods. Some examples: java.util.List/Map/Set: All methods in java.util.Collections should also be made available on the appropriate java collections API interface. java.io.Closeable: should contain a utility method 'closeAndIgnoreException' (arguably better suited on InputStream instead). java.util.List/Set: Should contain an 'of' method that makes unmodifiable lists and sets via varargs. java.io.FileFilter: Should contain an 'ofExtension(String)' method that creates a FileFilter for the provided extension. REFLECTIVE APIS: Currently, synthetic members are not treated specially by the reflection API. Therefore, this proposal does not require any reflective API changes. However, if transparency of the static method in interfaces proposal is required for the reflection API, the following 4 changes need to be made: There are 3 methods in java.lang.Class which need minor changes: getMethod(), getDeclaredMethods(), and getMethods(). These method finders will need to presume all static methods in a member type called $Methods are considered part of the type itself, and thus need to be returned as well, if the class object represents an interface. Because getDeclaredMethods() doesn't return methods in supertypes, and getMethod()/getMethods() only return accessible members of supertypes, none of these methods need to look in $Methods inner types of supertypes. These methods just need to look in the actual interface represented by the class object for a $Methods. There is one method in java.lang.Method that needs a minor change: the getDeclaringClass() method needs to return the Class object representing the interface, and not the $Methodssynthetic class, when invoked on a static method of an interface. OTHER CHANGES: No changes required. MIGRATION: No migration is needed. However, any java projects that currently employ utility classes (defined as having a private constructor that is not called anywhere in scope) which either return interface types, or take as first parameter an interface type, or both, where all previously mentioned interfaces are in the same package, are likely candidates for moving or copying to the relevant interface. Thus, IDEs can offer refactor advice to perform this task automatically and to find likely candidates. Such a refactor tool would for example identify all methods injava.util.Collections. COMPATIBILITY BREAKING CHANGES: Existing source that already uses an inner type named $Methods in an interface will change semantics when this proposal is implemented, primarily when queried via reflection. Between the vanishingly small odds of both a $Methods already existing and its methods being queried by the reflection API, and the general rule that $ should only be used in type names by compilers, the potential breaking change is hardly worth mentioning. EXISTING PROGRAMS: Existing programs are not affected by this change, other than as described above in the 'breaking changes' section. REFERENCES EXISTING BUGS: None. URL FOR PROTOTYPE (optional): None. From jjb at google.com Tue Mar 3 17:47:52 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 17:47:52 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> Message-ID: <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> I have modified the proposal in light of Mark's example. The only change is that the Disposable interface is no longer parameterized. This eliminates the incompatibility noted by Neal; so far as I know, the revised proposal introduces no incompatibilities. It can be found here: http://docs.google.com/Doc?id=ddv8ts74_0vnstdfdh . Happy reading, Josh From jjb at google.com Tue Mar 3 17:22:12 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 17:22:12 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> Message-ID: <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> Mark, Sorry for the delay, and thanks so much for the report! This is an interesting case. It seems unfortunate that DataCacheManagerImpl extends Closeable, given that its close method doesn't throw any checked exceptions. But it got me thinking, and I came to the conclusion that there's no reason for the Disposable interface to be parameterized! Its close method should just throw Exception. Then Closeable and DataCacheManager can both extend Disposable. The Disposable interface won't be terribly useful as a parameter type, but who cares? Its raison d'etre is the automatic resource management statement. In this context, the close method is invoked on a resource using its declared type. That means that it throws whatever exceptions it's declared to throw (as per the desugaring in my proposal). I will modify the proposal accordingly and repost it. I think this is a real improvement! It's both simpler and more broadly applicable. Thanks so much, Josh On Sun, Mar 1, 2009 at 1:54 AM, Mark Mahieu wrote: > > On 28 Feb 2009, at 19:08, Joshua Bloch wrote: > > Neal, >> >> On Sat, Feb 28, 2009 at 7:41 AM, Neal Gafter wrote: >> >> Josh- >>> >>> The compatibility section must document incompatibilities, whether or >>> not you judge them likely to cause problems in practice. >>> >> >> >> Good point. I will add this one. And I am still interested in whether >> anyone can find some code in an existing codebase that tickles this. >> >> > > Josh, > > The worst case I've turned up so far is the following, which would not be > broken by your proposal, but I think it would be restricted in its ability > to take advantage of it without further changes downstream: > > http://openjpa.apache.org/builds/1.2.0/apache-openjpa-1.2.0/docs/ > javadoc/org/apache/openjpa/datacache/DataCacheManagerImpl.html > > Here, the class DataCacheManagerImpl implements two interfaces, both of > which could logically be retrofitted with Disposable, but doing so would > then break DataCacheManagerImpl since different type arguments would be > needed (Exception and RuntimeException). > > (I think the idea is that an alternative implementation of DataCacheManager > can be specified by the user of this library; it seems quite likely that > these would extend the default DataCacheManagerImpl implementation.) > > Depends on how ticklish you are I guess. For me it's a hint that an > interface may not be the best mechanism. > > Regards, > > Mark > > From neal at gafter.com Tue Mar 3 18:08:12 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 18:08:12 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> Message-ID: <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> Given all the gnashing of teeth over the fact that Closeable's close method throws IOException, I can only imagine the pain that Disposable.close() throwing Exception will cause. On Tue, Mar 3, 2009 at 5:47 PM, Joshua Bloch wrote: > I have modified the proposal in light of Mark's example. ?The only change is > that the Disposable interface is no longer parameterized. ?This eliminates > the incompatibility noted by Neal; so far as I know, the revised proposal > introduces no incompatibilities. It can be found here: > http://docs.google.com/Doc?id=ddv8ts74_0vnstdfdh . > ? ? Happy reading, > > ? ? Josh > > From neal at gafter.com Tue Mar 3 18:16:12 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 18:16:12 -0800 Subject: Automatic Resource Management and Simple Resource Clean-up In-Reply-To: <49AD9EBE.5010808@vanellen.de> References: <49AD9EBE.5010808@vanellen.de> Message-ID: <15e8b9d20903031816q64e74c5apf8cb7792f34a46a6@mail.gmail.com> Thorsten- I think you're on the right track when you suggest the resource management library to encapsulate the implementation of proper resource management. A library solution could be flexible enough to handle the more complex cases like transactions too. Regards, Neal On Tue, Mar 3, 2009 at 1:18 PM, Thorsten van Ellen wrote: > Josh, Neal and Roger! > > I have had this idea also for a long time. I think it is in a "tradition" of > java of suppressing typical programming errors. A good example for the tradition > is automatic memory management and garbage collection that is a very complex > mechanism to avoid one very typical programming error. > > Management of resources other than memory usually is really as buggy as memory > management. My observation is that resource management is one of the most > frequent bug pattern I know of. Look at any project: you hardly find correct > optimal implemented examples and you nearly always find bugs in every non > trivial project. Analysing/finding the bug often is very difficult like finding > memory management bugs. > > It seems to me, the feature benefit is worth some more effort. The effort of > thinking a bit more about it might be not too much, especially if your heading > toward a "minimal" solution like "simple clean up", but I don't know what is > "affordable" in jdk7-schedule. > > Just to put in some additional/new ideas and to "make the cake bigger" before it > is reduced to the optimal solution ("brain-storming", sometimes thinkind around > a corner helps): > > Both proposed solutions might have problems with resource management, that is > distributed/shared/spread between two or more separated methods. Such problems > might be solved with a kind of GOF-"pattern", interfaces and a tiny "resource > management library". > > And there exist even more complicated resource management problems like ACID > database transactions that do not only have one "close"-operation but two > (commit and rollback) and a more complex decision process between those. > > But regarding these additional ideas may also be counterproductive for a tiny > language modification that solves 98 % of the typical bugs and therefore may > also be ignored! > > Best regards > > Thorsten van Ellen > > From reinier at zwitserloot.com Tue Mar 3 18:26:13 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 4 Mar 2009 03:26:13 +0100 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> Message-ID: <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> The new Disposable idea makes this proposal much cleaner, Josh. I like it. Neal, could you perhaps elaborate on the pain that Disposable is going to cause? Insinuating that proposals are Bad Ideas without any specifics whatsoever seems better suited to some sort of voting cycle. On this mailing list it seems counter-productive to say the least. --Reinier Zwitserloot On Mar 4, 2009, at 03:08, Neal Gafter wrote: > Given all the gnashing of teeth over the fact that Closeable's close > method throws IOException, I can only imagine the pain that > Disposable.close() throwing Exception will cause. > > On Tue, Mar 3, 2009 at 5:47 PM, Joshua Bloch wrote: >> I have modified the proposal in light of Mark's example. The only >> change is >> that the Disposable interface is no longer parameterized. This >> eliminates >> the incompatibility noted by Neal; so far as I know, the revised >> proposal >> introduces no incompatibilities. It can be found here: >> http://docs.google.com/Doc?id=ddv8ts74_0vnstdfdh . >> Happy reading, >> >> Josh >> >> > From Joe.Darcy at Sun.COM Tue Mar 3 18:28:26 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Tue, 03 Mar 2009 18:28:26 -0800 Subject: Proposal: Elvis and Other Null-Safe Operators In-Reply-To: <1236114437.49ad9c05d493c@www.paradise.net.nz> References: <49AABBA2.3040009@joda.org> <1631da7d0903010948h140c15e9hf1ddef3a0b837c9e@mail.gmail.com> <49AD1B58.5060305@joda.org> <1236114437.49ad9c05d493c@www.paradise.net.nz> Message-ID: <49ADE74A.4060407@sun.com> cadenza at paradise.net.nz wrote: >> This will be very confusing when you use Foo from another part of your >> application and expect the value to be non-null and