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 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. > [snip] ... and such checking is done with the Checkers framework associated with JSR 308 that is built on top of annotation processing: http://groups.csail.mit.edu/pag/jsr308/ -Joe From jjb at google.com Tue Mar 3 18:29:08 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 18:29:08 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> Message-ID: <17b2302a0903031829n6cf2d920o7e3fbb1d1838669d@mail.gmail.com> Reiner, On Tue, Mar 3, 2009 at 6:26 PM, Reinier Zwitserloot wrote: > The new Disposable idea makes this proposal much cleaner, Josh. I like > it. > Thanks very much! I slapped myself on the forehead when I thought of it. Sometimes the simplest ideas are the hardest to think of. Josh From reinier at zwitserloot.com Tue Mar 3 15:11:41 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 4 Mar 2009 00:11:41 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903032200.28367.david.goodenough@linkchoose.co.uk> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <200903032104.58445.david.goodenough@linkchoose.co.uk> <974754BA-9815-4C98-B868-3D793AFEF79A@zwitserloot.com> <200903032200.28367.david.goodenough@linkchoose.co.uk> Message-ID: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> But it seems that we _would_ lose a thing or two with this proposal. For example, if a complete properties proposal supports full backwards compatibility and generates getters and setters, then we have a bunch of code around that uses the foo#bar notation, which is by then already outdated, and would in fact get in the way of using foo#bar notation as a shorthand for calling the appropriate getter/setter. I don't know if that is a desired syntax sugar, but the point is: Your proposal would effectively make it impossible to add that later, as it would already be shorthand for creating a Property object. The # and the backtick are the only easily typed symbols that have no meaning whatsoever in java right now. Using one up for an simplified properties proposal is another serious disdvantage. I don't think your proposal makes property support light enough to warrant its inclusion in project coin. That's not to say I have something against properties; on the contrary, I love the idea and I'm very impressed with the way properties work in JavaFX. All the more reason to get it right instead of using a bandage. --Reinier Zwitserloot On Mar 3, 2009, at 23:00, David Goodenough wrote: > 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 neal at gafter.com Tue Mar 3 18:47:57 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 18:47:57 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> Message-ID: <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> I guess I assumed you were aware why people complain about Closeable.close() throwing IOException. Josh alluded to this when he said that Disposable won't be terribly useful as a parameter type. When you pass it somewhere, the receiver must assume that the close() method throws any Exception, and that forces the receiver to write code to handle the whole Exception hierarchy. I think it's likely that programmers would want to pass a Disposable around so that the receiver can put a region of code under control of the resource (i.e. dispose it when the receiver arrives at some particular point of completion). I'm afraid this would just be trading one set of pain points for another. On Tue, Mar 3, 2009 at 6:26 PM, Reinier Zwitserloot wrote: > 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 crazybob at crazybob.org Tue Mar 3 19:16:27 2009 From: crazybob at crazybob.org (Bob Lee) Date: Tue, 3 Mar 2009 19:16:27 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> Message-ID: On Tue, Mar 3, 2009 at 6:47 PM, Neal Gafter wrote: > I guess I assumed you were aware why people complain about > Closeable.close() throwing IOException. Josh alluded to this when he > said that Disposable won't be terribly useful as a parameter type. > When you pass it somewhere, the receiver must assume that the close() > method throws any Exception, and that forces the receiver to write > code to handle the whole Exception hierarchy. I think it's likely > that programmers would want to pass a Disposable around so that the > receiver can put a region of code under control of the resource (i.e. > dispose it when the receiver arrives at some particular point of > completion). I'm afraid this would just be trading one set of pain > points for another. > I think the new Disposable interface will work out very nicely (we could also name it Resource instead, but that can be left for the EG). Bob From markmahieu at googlemail.com Tue Mar 3 19:39:16 2009 From: markmahieu at googlemail.com (Mark Mahieu) Date: Wed, 4 Mar 2009 03:39:16 +0000 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> Message-ID: So would APIs be encouraged to define more specific Resource interfaces that narrow the thrown exception types ... interface SQLResource extends Resource { void dispose() throws SQLException { } } interface SWTResource extends Resource { void dispose() throws SWTException { } } etc? Mark On 4 Mar 2009, at 03:16, Bob Lee wrote: > On Tue, Mar 3, 2009 at 6:47 PM, Neal Gafter wrote: > >> I guess I assumed you were aware why people complain about >> Closeable.close() throwing IOException. Josh alluded to this when he >> said that Disposable won't be terribly useful as a parameter type. >> When you pass it somewhere, the receiver must assume that the close() >> method throws any Exception, and that forces the receiver to write >> code to handle the whole Exception hierarchy. I think it's likely >> that programmers would want to pass a Disposable around so that the >> receiver can put a region of code under control of the resource (i.e. >> dispose it when the receiver arrives at some particular point of >> completion). I'm afraid this would just be trading one set of pain >> points for another. >> > > I think the new Disposable interface will work out very nicely (we > could > also name it Resource instead, but that can be left for the EG). > > Bob > From jjb at google.com Tue Mar 3 19:41:18 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 19:41:18 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> Message-ID: <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> Neal, I think you may be missing the point here. The only use of this interface would be to make a type eligible for automatic resource management. It would never be used as a parameter type. There'd be no pain at all associated with it. Josh On Tue, Mar 3, 2009 at 6:47 PM, Neal Gafter wrote: > I guess I assumed you were aware why people complain about > Closeable.close() throwing IOException. Josh alluded to this when he > said that Disposable won't be terribly useful as a parameter type. > When you pass it somewhere, the receiver must assume that the close() > method throws any Exception, and that forces the receiver to write > code to handle the whole Exception hierarchy. I think it's likely > that programmers would want to pass a Disposable around so that the > receiver can put a region of code under control of the resource (i.e. > dispose it when the receiver arrives at some particular point of > completion). I'm afraid this would just be trading one set of pain > points for another. > > On Tue, Mar 3, 2009 at 6:26 PM, Reinier Zwitserloot > wrote: > - Show quoted text - > > 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 jjb at google.com Tue Mar 3 19:47:07 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 19:47:07 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> Message-ID: <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> Mark, I don't see a compelling need for it. When in doubt, leave it out. Josh On Tue, Mar 3, 2009 at 7:39 PM, Mark Mahieu wrote: > So would APIs be encouraged to define more specific Resource > interfaces that narrow the thrown exception types ... > > interface SQLResource extends Resource { > void dispose() throws SQLException { } > } > > interface SWTResource extends Resource { > void dispose() throws SWTException { } > } > > etc? > I don't think there'd be any reason to do this. From mr at sun.com Tue Mar 3 19:55:01 2009 From: mr at sun.com (Mark Reinhold) Date: Tue, 03 Mar 2009 19:55:01 -0800 Subject: Simple Resource Clean-up In-Reply-To: neal@gafter.com; Tue, 03 Mar 2009 10:47:31 PST; <15e8b9d20903031047q235815d5i669b93575fefba75@mail.gmail.com> Message-ID: <20090304035501.866A4D06B@callebaut.niobe.net> > Date: Tue, 03 Mar 2009 10:47:31 -0800 > From: Neal Gafter > 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). I completely agree. Annotations are, well, annotations. > The fact that this kind of flexibility is required suggests the > facility should be provided by libraries rather than hardcoded into > the language. If the only way for a library to support this kind of facility is for closures to be part of JDK 7, then this facility will not be in JDK 7. Now maybe I'm missing something, but unless one is going to recommend that developers use clunky nested classes for this sort of thing then I don't see how to implement this in a library -- absent closures. - Mark From neal at gafter.com Tue Mar 3 20:19:55 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 20:19:55 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> Message-ID: <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> I think you're missing the point, Josh. People do this today with Closeable, because that's the closest interface available that could be used to perform this function, but clients suffer from its exception signature. Disposable is better in one way - it would be retrofitted onto more classes - but much worse in its exception signature. You're saying that there's no pain because you can't use it as a parameter type. I'm saying that is the cause of the pain. The language construct that you're proposing does not supplant this technique of resource management, but the APIs you're proposing to go with it interfere with the technique. On Tue, Mar 3, 2009 at 7:41 PM, Joshua Bloch wrote: > Neal, > I think you may be missing the point here. ?The only use of this interface > would be to make a type eligible for automatic resource management. ?It > would never be used as a parameter type. ?There'd be no pain at all > associated with it. > ?? ? ? ? ?Josh > > On Tue, Mar 3, 2009 at 6:47 PM, Neal Gafter wrote: >> >> I guess I assumed you were aware why people complain about >> Closeable.close() throwing IOException. ?Josh alluded to this when he >> said that Disposable won't be terribly useful as a parameter type. >> When you pass it somewhere, the receiver must assume that the close() >> method throws any Exception, and that forces the receiver to write >> code to handle the whole Exception hierarchy. ?I think it's likely >> that programmers would want to pass a Disposable around so that the >> receiver can put a region of code under control of the resource (i.e. >> dispose it when the receiver arrives at some particular point of >> completion). ?I'm afraid this would just be trading one set of pain >> points for another. >> >> On Tue, Mar 3, 2009 at 6:26 PM, Reinier Zwitserloot >> wrote: >> - Show quoted text - >> > 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 neal at gafter.com Tue Mar 3 20:24:57 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 20:24:57 -0800 Subject: Simple Resource Clean-up In-Reply-To: <20090304035501.866A4D06B@callebaut.niobe.net> References: <15e8b9d20903031047q235815d5i669b93575fefba75@mail.gmail.com> <20090304035501.866A4D06B@callebaut.niobe.net> Message-ID: <15e8b9d20903032024g3493a915k5c51f04bda2ab692@mail.gmail.com> On Tue, Mar 3, 2009 at 7:55 PM, Mark Reinhold wrote: >> The fact that this kind of flexibility is required suggests the >> facility should be provided by libraries rather than hardcoded into >> the language. > > If the only way for a library to support this kind of facility is for > closures to be part of JDK 7, then this facility will not be in JDK 7. > > Now maybe I'm missing something, but unless one is going to recommend > that developers use clunky nested classes for this sort of thing then > I don't see how to implement this in a library -- absent closures. Right; addressing this set of problems is probably best left until they can be addressed in a more comprehensive way. From crazybob at crazybob.org Tue Mar 3 20:32:51 2009 From: crazybob at crazybob.org (Bob Lee) Date: Tue, 3 Mar 2009 20:32:51 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> Message-ID: Neal, it might help if you cited some specific examples. I've never personally suffered from Closeable's exception signature, and I can't imagine suffering from that of Disposable. I have suffered from the fact that no one seems to close resources correctly, and I'd love to have this feature whether we get closures one day or not. Bob On Tue, Mar 3, 2009 at 8:19 PM, Neal Gafter wrote: > I think you're missing the point, Josh. People do this today with > Closeable, because that's the closest interface available that could > be used to perform this function, but clients suffer from its > exception signature. Disposable is better in one way - it would be > retrofitted onto more classes - but much worse in its exception > signature. You're saying that there's no pain because you can't use > it as a parameter type. I'm saying that is the cause of the pain. > The language construct that you're proposing does not supplant this > technique of resource management, but the APIs you're proposing to go > with it interfere with the technique. > From neal at gafter.com Tue Mar 3 21:00:07 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 21:00:07 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <57AC202F-57F8-464F-B7AA-2992025C038D@twistedbanana.demon.co.uk> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> Message-ID: <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> See http://www.two-sdg.demon.co.uk/curbralan/papers/AnotherTaleOfTwoPatterns.pdf for a discussion of the pattern. With closures in the language, you'd get the possibility of more flexible resource management than is provided by this proposal. For example, you could write APIs to provide convenient support for the use of java.util.concurrent.locks.Lock, java.util.concurrent.locks.ReadWriteLock, transactions that can either be committed or rolled back, etc, without requiring the language commit itself to a single pattern. Worse: a single pattern that we would have to get right in the next ~3 months. These and other resource management patterns in use today simply don't fit into the mold of this proposal. That is a warning sign that a language construct directly encoding the pattern is inappropriate. -Neal On Tue, Mar 3, 2009 at 8:32 PM, Bob Lee wrote: > Neal, it might help if you cited some specific examples. I've never > personally suffered from Closeable's exception signature, and I can't > imagine suffering from that of Disposable. I have suffered from the fact > that no one seems to close resources correctly, and I'd love to have this > feature whether we get closures one day or not. > > Bob > > On Tue, Mar 3, 2009 at 8:19 PM, Neal Gafter wrote: >> >> I think you're missing the point, Josh. ?People do this today with >> Closeable, because that's the closest interface available that could >> be used to perform this function, but clients suffer from its >> exception signature. ?Disposable is better in one way - it would be >> retrofitted onto more classes - but much worse in its exception >> signature. ?You're saying that there's no pain because you can't use >> it as a parameter type. ?I'm saying that is the cause of the pain. >> The language construct that you're proposing does not supplant this >> technique of resource management, but the APIs you're proposing to go >> with it interfere with the technique. > > From crazybob at crazybob.org Tue Mar 3 21:53:38 2009 From: crazybob at crazybob.org (Bob Lee) Date: Tue, 3 Mar 2009 21:53:38 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> Message-ID: On Tue, Mar 3, 2009 at 9:00 PM, Neal Gafter wrote: > See > http://www.two-sdg.demon.co.uk/curbralan/papers/AnotherTaleOfTwoPatterns.pdf > for a discussion of the pattern. It's interesting to note that the author (a supposed expert) doesn't close resources properly, i.e. he lets exceptions from close() eat earlier, likely more informative exceptions. He would definitely benefit from this feature. With closures in the language, you'd > get the possibility of more flexible resource management than is > provided by this proposal. I wouldn't mind having closures one day, but based on the current state of the BGGA proposal, I think I'd like to have Automatic Resource Management either way, preferably sooner rather than later. To help illustrate, can you please show us what this snippet would look like using BGGA closures? try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } catch (IOException e) { showDialog("Copy failed."); } For example, you could write APIs to > provide convenient support for the use of > java.util.concurrent.locks.Lock, > java.util.concurrent.locks.ReadWriteLock > I'm not too worried about locks. They're significantly simpler than closing I/O resources in that you don't have to worry about unlock() throwing and you don't have to nest the try blocks. Unlike closing I/O resources, most people get locks right (if they use them at all). > , transactions that can either > be committed or rolled back, etc, without requiring the language > commit itself to a single pattern. The current proposal supports existing transaction approaches just fine. Either your API auto-commits (in which case you roll back if someone calls setRollbackOnly() on the resource), or you have to explicitly commit: try (Transaction t = ...; TransactionalResource tr = ...) { // do some stuff w/ tr ... t.commit(); } If you don't commit(), the tx gets rolled back. Honestly though, I don't see too many users leaving framework-based transaction solutions (like @Transactional) behind for this or BGGA closures. Worse: a single pattern that we > would have to get right in the next ~3 months. These and other > resource management patterns in use today simply don't fit into the > mold of this proposal. That is a warning sign that a language > construct directly encoding the pattern is inappropriate. I disagree. I think we know exactly how to close I/O resources already. The only reason there is any debate today is because doing the right thing in the absence of this feature is such a PITA. It's very difficult to do the right thing today; in contrast, this feature makes it easier to do the right thing than the wrong thing. Bob From neal at gafter.com Tue Mar 3 22:13:32 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 22:13:32 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> Message-ID: <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> On Tue, Mar 3, 2009 at 9:53 PM, Bob Lee wrote: > I wouldn't mind having closures one day, but based on the current state of > the BGGA proposal, I think I'd like to have Automatic Resource Management > either way, preferably sooner rather than later. To help illustrate, can you > please show us what this snippet would look like using BGGA closures? > > ? try (InputStream in = new FileInputStream(src); > ?? ?? OutputStream out = new FileOutputStream(dest)) { > ??? byte[] buf = new byte[8 * 1024]; > ??? int n; > ? ? while ((n = in.read(buf)) >= 0) > ? ? ? out.write(buf, 0, n); > ? } catch (IOException e) { > ??? showDialog("Copy failed."); > ? } It depends on what libraries are provided, but I'd expect it to be something like try { with (InputStream in : new FileInputStream(src)) with (OutputStream out : new FileOutputStream(dest)) { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } catch (IOException ex) { showDialog("Copy failed."); } Looks about as nice, except for the advantage that the semantics don't have to be hardcoded into the language. Can you please show me how to handle the following BGGA example using this proposal: lockWrite(lock) { clientCount++; } lockRead(lock) { return field.getValue(); } From crazybob at crazybob.org Tue Mar 3 22:44:36 2009 From: crazybob at crazybob.org (Bob Lee) Date: Tue, 3 Mar 2009 22:44:36 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> Message-ID: On Tue, Mar 3, 2009 at 10:13 PM, Neal Gafter wrote: > It depends on what libraries are provided, but I'd expect it to be > something like > > try { > with (InputStream in : new FileInputStream(src)) > with (OutputStream out : new FileOutputStream(dest)) { > byte[] buf = new byte[8 * 1024]; > int n; > while ((n = in.read(buf)) >= 0) > out.write(buf, 0, n); > } > } catch (IOException ex) { > showDialog("Copy failed."); > } > > Looks about as nice, except for the advantage that the semantics don't > have to be hardcoded into the language. FWIW, the lack of {} after the first with() cause me to take a double take. The BGGA version is verbose and user-unfriendly enough that I'd still want Automatic Resource Management. Closing I/O resources properly is one of the biggest challenges for Java programmers; it deserves a first class solution. Can you please show me how to > handle the following BGGA example using this proposal: > > lockWrite(lock) { > clientCount++; > } > lockRead(lock) { > return field.getValue(); > } You can't, nor does the proposal attempt to address this use case. I'm not personally interested in addressing that use case at this time because it's easy enough to write: writeLock.lock(); clientCount++; writeLock.unlock(); readLock.lock(); try { return field.getValue(); } finally { readLock.unlock(); } and save yourself two allocations and an implicit layer of indirection. Bob From jjb at google.com Tue Mar 3 23:00:55 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 23:00:55 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> Message-ID: <17b2302a0903032300i29b11512u5a6c591f1dcd184a@mail.gmail.com> Neal, > I'd expect it to be something like > > try { > with (InputStream in : new FileInputStream(src)) > with (OutputStream out : new FileOutputStream(dest)) { > byte[] buf = new byte[8 * 1024]; > int n; > while ((n = in.read(buf)) >= 0) > out.write(buf, 0, n); > } > } catch (IOException ex) { > showDialog("Copy failed."); > } > > Looks about as nice, No it doesn't. Not even close. In java, the colon in this position would be read by the typical programmer as "in" (e.g., "for each String s in stringList"). What we want (and what my proposal provides) is the equals sign (=), which means assignment. Also you have an extra level of nesting for each variable. This is one of the things that we're trying to get away from with this proposal. A more honest indentation for your syntax would be: try { with (InputStream in : new FileInputStream(src)) { with (OutputStream out : new FileOutputStream(dest)) { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } } catch (IOException ex) { showDialog("Copy failed."); } That's three levels off indentation instead of one (more generallly, number of resources + 1, instead of 1). Josh From neal at gafter.com Tue Mar 3 23:23:12 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 23:23:12 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903032300i29b11512u5a6c591f1dcd184a@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> <17b2302a0903032300i29b11512u5a6c591f1dcd184a@mail.gmail.com> Message-ID: <15e8b9d20903032323j6ee0ac5el6dcb2d4726832921@mail.gmail.com> On Tue, Mar 3, 2009 at 11:00 PM, Joshua Bloch wrote: > Neal, >> >> ?I'd expect it to be?something like >> >> try { >> ? ?with (InputStream in : new FileInputStream(src)) >> ? ? ? ? ? ?with (OutputStream out : new FileOutputStream(dest)) { >> ? ? ? ?byte[] buf = new byte[8 * 1024]; >> ? ? ? ?int n; >> ? ? ? ?while ((n = in.read(buf)) >= 0) >> ? ? ? ? ? ?out.write(buf, 0, n); >> ? ?} >> } catch (IOException ex) { >> ? ?showDialog("Copy failed."); >> } >> >> Looks about as nice, > > No it doesn't. ?Not even close. In java, the colon in this position would be > read by the typical programmer as "in" ?(e.g., "for each String s in > stringList"). Java programmers already know that ":" doesn't mean "in" except after "for"; they do after all somehow manage to understand labels and assert statements. I think it's a stretch to suggest that anyone would be tempted to read it that way except to make this argument. Java programmers tend to see a close paren followed by a semicolon at the end of a line as the end of a statement, but as you can see from Bob's example, they're likely to be confused by this ARM proposal. > What we want (and what my proposal provides) is the equals > sign (=), which means assignment. Clearly, there is far more than a simple assignment going on in this code, or there would be little point in suggesting a new language feature. Therefore relying on the intuition of assignment is also misleading. > Also you have an extra level of nesting > for each variable. Just as one does not add a level of indentation for each successive element in a chain of if-then-else statements, one does not add a level of indentation for each resource being managed. You can certainly elect to use an additional block and an additional level of nesting for each variable if you feel it makes the code more clear, and I know you've been preaching that BGGA control invocations should be written that way, but I find the way I wrote it more clear. From jjb at google.com Tue Mar 3 23:27:05 2009 From: jjb at google.com (Joshua Bloch) Date: Tue, 3 Mar 2009 23:27:05 -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: <17b2302a0903032327p333492f5l72a1d939e2005b33@mail.gmail.com> Per Joe Darcy's request, I'm including a copy of modified version of the proposal. The text below is properly formatted in this e-mail, but I'm afraid that mailman will eat the formatting:( Automatic Resource Management *AUTHOR: *Joshua Bloch *OVERVIEW* FEATURE SUMMARY: A *resource* is as an object that must be closed manually, such as a java.io.InputStream, OutputStream, Reader, Writer, Formatter; java.nio.Channel; java.net.socket; java.sql.Connection, Statement, ResultSet, or java.awt.Graphics. The *automatic resource management statement* is a form of the try statement that declares one or more resources. The scope of these resource declarations is limited to the statement. When the statement completes, whether normally or abruptly, all of its resources are closed automatically. MAJOR ADVANTAGE: The automatic resource management statement obviates the need for manual resource termination, which has proven ugly and error prone. Even good programmers get it wrong most of the time. For example, Sun?s guide to Persistent Connections (http://tinyurl.com/6b5jc7) gets it wrong in code that claims to be exemplary. Likewise, the solution on page 88 of Bloch and Gafter?s *Java Puzzlers* (Addison-Wesley, 2006) is badly broken, and no one ever noticed. In fact, 2/3 of the uses of the close method in the JDK itself are wrong! The price for failing to terminate resources properly is resource leaks or even outright failures, which may be silent (as in *Java Puzzlers*). Even the ?correct? idioms for manual resource management are deficient: if an exception is thrown in the try block, and another when closing the resource in the finally block, the second exception supplants the first, making it difficult to determine the real cause of the trouble. While it is possible to write code to suppress the second exception in favor of the first, virtually no one does, as it is just too verbose. This is not a theoretical problem; it has greatly complicated the debugging of large systems. A secondary advantage of the automatic resource management construct is that it could emit the code to suppress the uninteresting (second) exception in favor of the interesting (first) one with no effort on the part of the programmer, and no loss to the clarity of the program. Like the for-each statement (introduced in Java 1.5), the automatic resource management statement is a small piece of syntactic sugar with a very high power-to-weight ratio. MAJOR DISADVANTAGE: Like all syntactic sugar, this construct removes a bit of Java?s ?what you see is what you get? character (?transparency?). ALTERNATIVES: The benefits of this proposal cannot be had without a language change. Absent a language change, you must close resources manually. That is why Java?s competitors have automatic resource management constructs (C# has using blocks and C++ has destructors). *EXAMPLES* SIMPLE EXAMPLE: Here is a static method to read the first line of a file, demonstrating the minimal (nearly) correct code to release a single resource today. static String readFirstLineFromFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } } Unfortunately, if the readLine and close invocations both throw exceptions, the latter exception supplants the former. The only practical way around this today would to be to ignore any exception thrown by the close invocation. While this might be reasonable in the case of a Reader or InputStream, it would be disastrous for a Writer or OutputStream. Here?s how it would look with an automatic resource management statement: static String readFirstLineFromFile2(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); } } ADVANCED EXAMPLE*:* Here is a static method to make a copy of a file, demonstrating the minimal correct code to release two resources today: static void copy(String src, String dest) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dest); try { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { out.close(); } } finally { in.close(); } } Here?s how it would look with an automatic resource management statement: static void copy(String src, String dest) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8192]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } *DETAILS* * * SPECIFICATION: What follows is not intended to be a formal JLS-quality specification. It emphasizes brevity and clarity over thoroughness. SYNTAX: The production for *TryStatement* in JLS ?14.20 would be extended with this alternative: *TryStatement*: try ( *ResourceDeclarations* ) *Block Catchesopt Finallyopt* *ResourceDeclarations*: *LocalVariableDeclaration* *LocalVariableDeclaration* ; *ResourceDeclarations* * * The type of each *LocalVariableDeclaration* in a *ResourceDeclarations *must be a subtype of Disposable. Such types are known as *resource types*. SEMANTICS and COMPILATION: An automatic resource management statement with a single local variable declaration and no *Finally* or *Catches* would behave as if replaced by the following source code: { final *LocalVariableDeclaration* ; try *Block* finally { *localVar*.close(); // *localVar* is the variable declared in * LocalVariableDeclaration* } } An automatic resource management statement with multiple local variable declarations and no *Finally* or *Catches* would behave as if (recursively) replaced by the following source code: { final *LocalVariableDeclaration* ; // First variable declaration try( *ResourceDeclarations* ) *Block* finally { // Remaining resource declarations *localVar*.close(); // *localVar* is the variable declared in * LocalVariableDeclaration* } } When you initially de-sugar an automatic resource management statement with n resource declarations for n > 1, you get an automatic resource management statement with n-1 resource declarations. After n such replacements, you have n nested try-finally statements, and the de-sugaring is complete. Note that resource declarations are implicitly final. For consistency with existing constructs with implicit modifiers, it is legal (though discouraged) for the programmer to provide an explicit final modifier. Note that the close method is only called on resources whose declarations execute without throwing an exception, and that the first such exception causes the statement to complete abruptly. An automatic resource management statement with a *Finally* or *Catches* would behave as if replaced by the following code (which contains an automatic resource management statement with no *Finally* or*Catches that must be expanded as per the desugaring above*): try { try ( *ResourceDeclarations* ) *Block* } *Finallyopt Catchesopt* These simple semantics solve most of the problems described above, but they leave one problem unsolved: if the *Block* throws one exception, and the automatically generated close invocation throws another, the latter exception supplants the former. This could be corrected by using a slightly more complex de-sugaring for the single-local-variable-declaration form of the construct: { final LocalVariableDeclaration ; boolean #suppressSecondaryException = false; try Block catch (final Throwable #t) { #suppressSecondaryException = true; throw #t; } finally { if (#suppressSecondaryException) try { localVar.close(); } catch(Exception #ignore) { } else localVar.close(); } } The variables #t, #suppressSecondaryException, and #ignore are compiler-generated identifiers that are distinct from one and other, and from any other identifiers (compiler-generated or otherwise) that are in scope (JLS ?6.3) at the point where the automatic resource management statement occurs. This de-sugaring takes advantage of the ability to rethrow a final caught exception, which has been proposed for Java 7. The present proposal does * not* depend on this ability. In its absence, one could use a method such as sneakyThrow (*Java Puzzlers*, Puzzle 43). TYPE SYSTEM: The proposal has no effect on the type system. TESTING: The proposed construct can be tested by writing automatic resource management statements with a number of resources varying from 1 to some upper limit (say 10). Each resource can throw an exception (or not) during initialization, use, or termination. JUnit assertions are added to check that all resources opened are automatically closed, and that the correct exception (if any) is thrown. LIBRARY SUPPORT: A class must implement a designated interface to make it eligible for automatic resource management. An obvious choice would be Closeable, but unfortunately its close method is specified to throw IOException, which precludes its use in a general purpose resource management facility. It is, however, possible to retrofit Closeable with a superinterface: *package** java.lang;* */*** * * A resource that must be closed when it is no longer needed.* * */* *public interface Disposable {* * void close() throws Exception;* *}* package java.io; public interface Closeable *extends Disposable* { void close() throws IOException; } Other existing classes and interfaces can be similarly retrofitted, for example: package java.sql; interface Connection *extends Disposable* { void close() throws SQLException; ... // (and all the other members of the Connection interface) } REFLECTIVE APIS: This proposal has no effect on core reflective APIs. The tree API inside javac ( http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) would require a minor extension. OTHER CHANGES: No other parts of the platform need be to be updated. MIGRATION: Any resource that must be closed manually should be retrofitted to implement the Disposable interface. In the JDK, this includes java.io.Closeable; java.sql.Connection, Statement, and ResultSet. New code using classes that implement Disposable should use automatic resource management statements (for clarity and correctness). Manual resource management in existing code can be replaced by automatic resource management for increased clarity and improved behavior. Given the number of resource management errors observed in existing code, it may be worth the time to do this systematically. It is very easy to do this with any modern IDE, which can search for uses of a method (in this case, Disposable.close()). *COMPATIBILITY* * * BREAKING CHANGES: All previously valid programs remain valid, and their semantics is unaffected. * * EXISTING PROGRAMS: Source and class files of earlier versions are unaffected by the feature. No new overloadings or overridings can occur. *REFERENCES* * * EXISTING BUGS: 4888664, 4364906, 4331290, 4215007, 4120342. *ADDITIONAL FEATURES* Here are several features that might be added to the construct if the expert group deemed it advisable: *Retaining suppressed exceptions* - As described above, the construct simply discards exceptions that are suppressed. It would probably be better to attach them to the exception in whose favor they are being suppressed. This would entail adding two new methods to Throwable, void addSuppressedException(Throwable) and Throwable[] getSuppressedExceptions(). *Ignoring certain **close failures* - One shortcoming of the construct as described is that it does not provide a way for the programmer to indicate that exceptions thrown when closing a resource should be ignored. In the case of the copy method, ideally the program would ignore exceptions thrown when closing the InputStream, but not the OutputStream. There are several ways this could be achieved. *Expressions in place of declarations* - It was suggested that the automatic resource management statement could be defined to allow an expression in place of a variable declaration, permitting the use of preexisting variables. This feature was consciously omitted to make it more difficult to access a closed resource accidentally. *DESIGN ALTERNATIVES* *Modifier in place of block* - An alterative to a block construct is a new modifier that could be added to any local variable declaration for a variable that extends Disposable. This is more flexible and less verbose, but more dissimilar to existing Java language constructs. *Annotation to indicate termination method *- An alternative to the proposed use of the Disposable interface is an annotation on the resource termination method. This 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. Edit this page (if you have permission) | Google Docs -- Web word processing, presentations and spreadsheets. From neal at gafter.com Tue Mar 3 23:37:37 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 23:37:37 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> Message-ID: <15e8b9d20903032337q49561f8bj52f67ec093385e97@mail.gmail.com> On Tue, Mar 3, 2009 at 9:53 PM, Bob Lee wrote: >> , transactions that can either >> be committed or rolled back, etc, without requiring the language >> commit itself to a single pattern. > > The current proposal supports existing transaction approaches just fine. > Either your API auto-commits (in which case you roll back if someone calls > setRollbackOnly() on the resource), or you have to explicitly commit: > > ? try (Transaction t = ...; TransactionalResource tr = ...) { > ? ? // do some stuff w/ tr > ? ? ... > ??? t.commit(); > ? } > > If you don't commit(), the tx gets rolled back. Bob- java.sql.Connection has three methods (among others): commit() - to cause the transaction to take effect rollback() - to undo the transaction close() - to close the connection Using the construct as you suggest closes the connection - not necessarily a good idea, and not the point of the example. The point is to commit() when the controlled statement completes normally, and rollback() when it terminates abnormally, without the programmer having to add further boilerplate. BGGA enables frameworks to provide an API that makes this as easy as if a purpose-built statement were available, but the present proposal appears to require boilerplate in each client. From jeremy.manson at gmail.com Tue Mar 3 23:49:39 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Tue, 3 Mar 2009 23:49:39 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> Message-ID: <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> On Tue, Mar 3, 2009 at 10:13 PM, Neal Gafter wrote: > ?Can you please show me how to > handle the following BGGA example using this proposal: > > lockWrite(lock) { > ? ?clientCount++; > } > lockRead(lock) { > ? ?return field.getValue(); > } > > As a side note to this conversation, directed at any people who will think you can't have this feature with this proposal, regardless of your feelings about the particular merits of accomplishing the same thing with closures, there *is* a way to handle this case: class LockDisposer implements Disposable { private final Lock lock; public LockDisposer(Lock l) { lock = l; lock.lock(); } public void close() { lock.unlock(); } } try (LockDisposer l = new LockDisposer(lock.readLock())) { clientCount++; } try (LockDisposer l = new LockDisposer(lock.writeLock())) { return field.getValue(); } I suspect a LOT of people will be doing something similar to this hack if this proposal is adopted. To make it much cleaner, you could first adjust this proposal so that the try statement can take an expression that returns a Disposable, and then you could adjust the Lock classes so that a) lock() returns this and b) they implement Disposable, at which point you could have: try (lock.readLock().lock()) { clientCount++; } try (lock.writeLock().lock()) { return field.getValue(); } Which is pretty clean. Note that Josh mentioned the possibility of try() taking an expression in his proposal. This is why. Jeremy From neal at gafter.com Tue Mar 3 23:56:29 2009 From: neal at gafter.com (Neal Gafter) Date: Tue, 3 Mar 2009 23:56:29 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> Message-ID: <15e8b9d20903032356s3db82efv141d9e014d315354@mail.gmail.com> On Tue, Mar 3, 2009 at 11:49 PM, Jeremy Manson wrote: > As a side note to this conversation, directed at any people who will > think you can't have this feature with this proposal, regardless of > your feelings about the particular merits of accomplishing the same > thing with closures, there *is* a way to handle this case: > > try (LockDisposer l = new LockDisposer(lock.readLock())) { > ?clientCount++; > } > > try (LockDisposer l = new LockDisposer(lock.writeLock())) { > ?return field.getValue(); > } Yow. I think the cure might be worse than the disease. > I suspect a LOT of people will be doing something similar to this hack > if this proposal is adopted. ?To make it much cleaner, you could first > adjust this proposal so that the try statement can take an expression > that returns a Disposable, and then you could adjust the Lock classes > so that a) lock() returns this and b) they implement Disposable, at > which point you could have: You can't make such changes to existing interfaces without breaking existing code. Changing the signature of lock() breaks existing callers, and adding a close() method (to implement Disposable) breaks existing implementations. From jeremy.manson at gmail.com Wed Mar 4 00:03:51 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Wed, 4 Mar 2009 00:03:51 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032356s3db82efv141d9e014d315354@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> <15e8b9d20903032356s3db82efv141d9e014d315354@mail.gmail.com> Message-ID: <1631da7d0903040003wd83e97bj53083703753d1bc8@mail.gmail.com> On Tue, Mar 3, 2009 at 11:56 PM, Neal Gafter wrote: > On Tue, Mar 3, 2009 at 11:49 PM, Jeremy Manson wrote: >> As a side note to this conversation, directed at any people who will >> think you can't have this feature with this proposal, regardless of >> your feelings about the particular merits of accomplishing the same >> thing with closures, there *is* a way to handle this case: >> >> try (LockDisposer l = new LockDisposer(lock.readLock())) { >> ?clientCount++; >> } >> >> try (LockDisposer l = new LockDisposer(lock.writeLock())) { >> ?return field.getValue(); >> } > > Yow. ?I think the cure might be worse than the disease. That's why I suggested changing try() so that it took an expression. The second version was, I think you will admit, much cleaner. >> I suspect a LOT of people will be doing something similar to this hack >> if this proposal is adopted. ?To make it much cleaner, you could first >> adjust this proposal so that the try statement can take an expression >> that returns a Disposable, and then you could adjust the Lock classes >> so that a) lock() returns this and b) they implement Disposable, at >> which point you could have: > > You can't make such changes to existing interfaces without breaking > existing code. ?Changing the signature of lock() breaks existing > callers, and adding a close() method (to implement Disposable) breaks > existing implementations. I'm probably being typically dumb, but I'm not sure how adding a method breaks anything. You don't *have* to change the signature of lock -- just add a new method (call it "disposeLock") that has the required semantics: try (lock.readLock().disposeLock()) { clientCount++; } try (lock.writeLock().disposeLock()) { return field.getValue(); } Jeremy From Joe.Darcy at Sun.COM Wed Mar 4 00:10:55 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 00:10:55 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903032327p333492f5l72a1d939e2005b33@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> <17b2302a0903032327p333492f5l72a1d939e2005b33@mail.gmail.com> Message-ID: <49AE378F.7090901@sun.com> Joshua Bloch wrote: > Per Joe Darcy's request, I'm including a copy of modified version of the > proposal. The text below is properly formatted in this e-mail, but I'm > afraid that mailman will eat the formatting:( > Automatic Resource Management > Hello. I've changed the mailman options so HTML should now go through; below will be Josh's proposal in HTML if all has gone as intended. -Joe Automatic Resource Management *AUTHOR: *Joshua Bloch *OVERVIEW* FEATURE SUMMARY: A /resource/ is as an object that must be closed manually, such as a java.io.InputStream, OutputStream, Reader, Writer, Formatter; java.nio.Channel; java.net.socket; java.sql.Connection, Statement, ResultSet, or java.awt.Graphics. The /automatic resource management statement/ is a form of the try statement that declares one or more resources. The scope of these resource declarations is limited to the statement. When the statement completes, whether normally or abruptly, all of its resources are closed automatically. MAJOR ADVANTAGE: The automatic resource management statement obviates the need for manual resource termination, which has proven ugly and error prone. Even good programmers get it wrong most of the time. For example, Sun?s guide to Persistent Connections (http://tinyurl.com/6b5jc7) gets it wrong in code that claims to be exemplary. Likewise, the solution on page 88 of Bloch and Gafter?s /Java Puzzlers/ (Addison-Wesley, 2006) is badly broken, and no one ever noticed. In fact, 2/3 of the uses of the close method in the JDK itself are wrong! The price for failing to terminate resources properly is resource leaks or even outright failures, which may be silent (as in /Java Puzzlers/). Even the ?correct? idioms for manual resource management are deficient: if an exception is thrown in the try block, and another when closing the resource in the finally block, the second exception supplants the first, making it difficult to determine the real cause of the trouble. While it is possible to write code to suppress the second exception in favor of the first, virtually no one does, as it is just too verbose. This is not a theoretical problem; it has greatly complicated the debugging of large systems. A secondary advantage of the automatic resource management construct is that it could emit the code to suppress the uninteresting (second) exception in favor of the interesting (first) one with no effort on the part of the programmer, and no loss to the clarity of the program. Like the for-each statement (introduced in Java 1.5), the automatic resource management statement is a small piece of syntactic sugar with a very high power-to-weight ratio. MAJOR DISADVANTAGE: Like all syntactic sugar, this construct removes a bit of Java?s ?what you see is what you get? character (?transparency?). ALTERNATIVES: The benefits of this proposal cannot be had without a language change. Absent a language change, you must close resources manually. That is why Java?s competitors have automatic resource management constructs (C# has using blocks and C++ has destructors). *EXAMPLES* SIMPLE EXAMPLE: Here is a static method to read the first line of a file, demonstrating the minimal (nearly) correct code to release a single resource today. static String readFirstLineFromFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } } Unfortunately, if the readLine and close invocations both throw exceptions, the latter exception supplants the former. The only practical way around this today would to be to ignore any exception thrown by the close invocation. While this might be reasonable in the case of a Reader or InputStream, it would be disastrous for a Writer or OutputStream. Here?s how it would look with an automatic resource management statement: static String readFirstLineFromFile2(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); } } ADVANCED EXAMPLE*:* Here is a static method to make a copy of a file, demonstrating the minimal correct code to release two resources today: static void copy(String src, String dest) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dest); try { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { out.close(); } } finally { in.close(); } } Here?s how it would look with an automatic resource management statement: static void copy(String src, String dest) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8192]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } *DETAILS* * * SPECIFICATION: What follows is not intended to be a formal JLS-quality specification. It emphasizes brevity and clarity over thoroughness. SYNTAX: The production for /TryStatement/ in JLS ?14.20 would be extended with this alternative: /TryStatement/: try ( /ResourceDeclarations/ ) /Block Catches_opt Finally_opt / /ResourceDeclarations/: /LocalVariableDeclaration/ /LocalVariableDeclaration/ ; /ResourceDeclarations/ / / The type of each /LocalVariableDeclaration/ in a /ResourceDeclarations /must be a subtype of Disposable. Such types are known as /resource types/. SEMANTICS and COMPILATION: An automatic resource management statement with a single local variable declaration and no /Finally/ or /Catches/ would behave as if replaced by the following source code: { final /LocalVariableDeclaration/ ; try /Block/ finally { /localVar/.close(); // /localVar/ is the variable declared in /LocalVariableDeclaration/ } } An automatic resource management statement with multiple local variable declarations and no /Finally/ or /Catches/ would behave as if (recursively) replaced by the following source code: { final /LocalVariableDeclaration/ ; // First variable declaration try( /ResourceDeclarations/ ) /Block/ finally { // Remaining resource declarations /localVar/.close(); // /localVar/ is the variable declared in /LocalVariableDeclaration/ } } When you initially de-sugar an automatic resource management statement with n resource declarations for n > 1, you get an automatic resource management statement with n-1 resource declarations. After n such replacements, you have n nested try-finally statements, and the de-sugaring is complete. Note that resource declarations are implicitly final. For consistency with existing constructs with implicit modifiers, it is legal (though discouraged) for the programmer to provide an explicit final modifier. Note that the close method is only called on resources whose declarations execute without throwing an exception, and that the first such exception causes the statement to complete abruptly. An automatic resource management statement with a /Finally/ or /Catches/ would behave as if replaced by the following code (which contains an automatic resource management statement with no /Finally/ or/Catches that must be expanded as per the desugaring above/): try { try ( /ResourceDeclarations/ ) /Block/ } /Finally_opt Catches_opt / These simple semantics solve most of the problems described above, but they leave one problem unsolved: if the /Block/ throws one exception, and the automatically generated close invocation throws another, the latter exception supplants the former. This could be corrected by using a slightly more complex de-sugaring for the single-local-variable-declaration form of the construct: { final LocalVariableDeclaration ; boolean #suppressSecondaryException = false; try Block catch (final Throwable #t) { #suppressSecondaryException = true; throw #t; } finally { if (#suppressSecondaryException) try { localVar.close(); } catch(Exception #ignore) { } else localVar.close(); } } The variables #t, #suppressSecondaryException, and #ignore are compiler-generated identifiers that are distinct from one and other, and from any other identifiers (compiler-generated or otherwise) that are in scope (JLS ?6.3) at the point where the automatic resource management statement occurs. This de-sugaring takes advantage of the ability to rethrow a final caught exception, which has been proposed for Java 7. The present proposal does /not/ depend on this ability. In its absence, one could use a method such as sneakyThrow (/Java Puzzlers/, Puzzle 43). TYPE SYSTEM: The proposal has no effect on the type system. TESTING: The proposed construct can be tested by writing automatic resource management statements with a number of resources varying from 1 to some upper limit (say 10). Each resource can throw an exception (or not) during initialization, use, or termination. JUnit assertions are added to check that all resources opened are automatically closed, and that the correct exception (if any) is thrown. LIBRARY SUPPORT: A class must implement a designated interface to make it eligible for automatic resource management. An obvious choice would be Closeable, but unfortunately its close method is specified to throw IOException, which precludes its use in a general purpose resource management facility. It is, however, possible to retrofit Closeable with a superinterface: *package** java.lang;* */*** * * A resource that must be closed when it is no longer needed.* * */* *public interface Disposable {* * void close() throws Exception;* *}* package java.io; public interface Closeable *extends Disposable* { void close() throws IOException; } Other existing classes and interfaces can be similarly retrofitted, for example: package java.sql; interface Connection *extends Disposable* { void close() throws SQLException; ... // (and all the other members of the Connection interface) } REFLECTIVE APIS: This proposal has no effect on core reflective APIs. The tree API inside javac (http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) would require a minor extension. OTHER CHANGES: No other parts of the platform need be to be updated. MIGRATION: Any resource that must be closed manually should be retrofitted to implement the Disposable interface. In the JDK, this includes java.io.Closeable; java.sql.Connection, Statement, and ResultSet. New code using classes that implement Disposable should use automatic resource management statements (for clarity and correctness). Manual resource management in existing code can be replaced by automatic resource management for increased clarity and improved behavior. Given the number of resource management errors observed in existing code, it may be worth the time to do this systematically. It is very easy to do this with any modern IDE, which can search for uses of a method (in this case, Disposable.close()). *COMPATIBILITY* * * BREAKING CHANGES: All previously valid programs remain valid, and their semantics is unaffected. * * EXISTING PROGRAMS: Source and class files of earlier versions are unaffected by the feature. No new overloadings or overridings can occur. *REFERENCES* * * EXISTING BUGS: 4888664, 4364906, 4331290, 4215007, 4120342. *ADDITIONAL FEATURES* Here are several features that might be added to the construct if the expert group deemed it advisable: *Retaining suppressed exceptions* - As described above, the construct simply discards exceptions that are suppressed. It would probably be better to attach them to the exception in whose favor they are being suppressed. This would entail adding two new methods to Throwable, void addSuppressedException(Throwable) and Throwable[] getSuppressedExceptions(). *Ignoring certain **close failures* - One shortcoming of the construct as described is that it does not provide a way for the programmer to indicate that exceptions thrown when closing a resource should be ignored. In the case of the copy method, ideally the program would ignore exceptions thrown when closing the InputStream, but not the OutputStream. There are several ways this could be achieved. *Expressions in place of declarations* - It was suggested that the automatic resource management statement could be defined to allow an expression in place of a variable declaration, permitting the use of preexisting variables. This feature was consciously omitted to make it more difficult to access a closed resource accidentally. *DESIGN ALTERNATIVES* *Modifier in place of block* - An alterative to a block construct is a new modifier that could be added to any local variable declaration for a variable that extends Disposable. This is more flexible and less verbose, but more dissimilar to existing Java language constructs. *Annotation to indicate termination method *- An alternative to the proposed use of the Disposable interface is an annotation on the resource termination method. This 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. From jjb at google.com Wed Mar 4 00:12:53 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 00:12:53 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <1631da7d0903040003wd83e97bj53083703753d1bc8@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> <15e8b9d20903032356s3db82efv141d9e014d315354@mail.gmail.com> <1631da7d0903040003wd83e97bj53083703753d1bc8@mail.gmail.com> Message-ID: <17b2302a0903040012u7c378912x37968c8941f26dd5@mail.gmail.com> A gentle reminder: this construct was designed for one thing and one thing only: resource management. It was not designed for locking. Java already contains a native construct for locking (synchronized). A very small minority of Java programmers use java.util.concurrent.atomic.Locks. Support for them is not a priority. Nearly all Java programmers use resources such as java.io.InputStream, OutputStream, Reader, Writer, Formatter; java.nio.Channel; java.net.socket; java.sql.Connection, Statement, ResultSet, or java.awt.Graphics. That's what this construct is designed for. Goodnight, Josh On Wed, Mar 4, 2009 at 12:03 AM, Jeremy Manson wrote: > On Tue, Mar 3, 2009 at 11:56 PM, Neal Gafter wrote: > > On Tue, Mar 3, 2009 at 11:49 PM, Jeremy Manson > wrote: > >> As a side note to this conversation, directed at any people who will > >> think you can't have this feature with this proposal, regardless of > >> your feelings about the particular merits of accomplishing the same > >> thing with closures, there *is* a way to handle this case: > >> > >> try (LockDisposer l = new LockDisposer(lock.readLock())) { > >> clientCount++; > >> } > >> > >> try (LockDisposer l = new LockDisposer(lock.writeLock())) { > >> return field.getValue(); > >> } > > > > Yow. I think the cure might be worse than the disease. > > That's why I suggested changing try() so that it took an expression. > The second version was, I think you will admit, much cleaner. > > >> I suspect a LOT of people will be doing something similar to this hack > >> if this proposal is adopted. To make it much cleaner, you could first > >> adjust this proposal so that the try statement can take an expression > >> that returns a Disposable, and then you could adjust the Lock classes > >> so that a) lock() returns this and b) they implement Disposable, at > >> which point you could have: > > > > You can't make such changes to existing interfaces without breaking > > existing code. Changing the signature of lock() breaks existing > > callers, and adding a close() method (to implement Disposable) breaks > > existing implementations. > > I'm probably being typically dumb, but I'm not sure how adding a > method breaks anything. You don't *have* to change the signature of > lock -- just add a new method (call it "disposeLock") that has the > required semantics: > > try (lock.readLock().disposeLock()) { > clientCount++; > } > > try (lock.writeLock().disposeLock()) { > return field.getValue(); > } > > Jeremy > > From crazybob at crazybob.org Wed Mar 4 00:16:39 2009 From: crazybob at crazybob.org (Bob Lee) Date: Wed, 4 Mar 2009 00:16:39 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903032337q49561f8bj52f67ec093385e97@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031941w5e9a0058geba9e693cb938555@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032337q49561f8bj52f67ec093385e97@mail.gmail.com> Message-ID: On Tue, Mar 3, 2009 at 11:37 PM, Neal Gafter wrote: > Bob- > > java.sql.Connection has three methods (among others): > commit() - to cause the transaction to take effect > rollback() - to undo the transaction > close() - to close the connection > > Using the construct as you suggest closes the connection - not > necessarily a good idea, and not the point of the example. The point > is to commit() when the controlled statement completes normally, and > rollback() when it terminates abnormally, without the programmer > having to add further boilerplate. BGGA enables frameworks to provide > an API that makes this as easy as if a purpose-built statement were > available, but the present proposal appears to require boilerplate in > each client. > Neal- Thanks for the tutorial. I've done quite a bit of JDBC and Java EE programming in the past (http://www.manning.com/tate2/), and I'm confident that the Automatic Resource Management proposal suits my needs just fine. :-) Bob From jeremy.manson at gmail.com Wed Mar 4 00:25:52 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Wed, 4 Mar 2009 00:25:52 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903040012u7c378912x37968c8941f26dd5@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903032019v1f967824m7785b87ac4887581@mail.gmail.com> <15e8b9d20903032100s29663ad5td870e0f444cbfc07@mail.gmail.com> <15e8b9d20903032213u2a94f9e1k2459c94fab31c30@mail.gmail.com> <1631da7d0903032349v2d92df07n6c7a7e756a5e42@mail.gmail.com> <15e8b9d20903032356s3db82efv141d9e014d315354@mail.gmail.com> <1631da7d0903040003wd83e97bj53083703753d1bc8@mail.gmail.com> <17b2302a0903040012u7c378912x37968c8941f26dd5@mail.gmail.com> Message-ID: <1631da7d0903040025o66665922ve46ec03af8f0e233@mail.gmail.com> Although this is clear from the proposal, intentions and uses have a way of diverging. As you know, the usage I showed is very similar to C++'s RAII idiom, a very similar abuse of constructors and destructors that uses similar ridiculous wrapper classes. Jeremy On Wed, Mar 4, 2009 at 12:12 AM, Joshua Bloch wrote: > A gentle reminder: this construct was designed for one thing and one thing > only: resource management. ?It was not designed for locking. ?Java already > contains a native construct for locking (synchronized). ?A very small > minority of Java programmers use?java.util.concurrent.atomic.Locks. ?Support > for them is not a priority. ?Nearly all Java programmers use resources such > as?java.io.InputStream,?OutputStream,?Reader,?Writer,?Formatter;?java.nio.Channel;?java.net.socket;?java.sql.Connection,?Statement,?ResultSet, > or?java.awt.Graphics. ?That's what this construct is designed for. > ?? ?Goodnight, > ?? ?Josh > On Wed, Mar 4, 2009 at 12:03 AM, Jeremy Manson > wrote: >> >> On Tue, Mar 3, 2009 at 11:56 PM, Neal Gafter wrote: >> > On Tue, Mar 3, 2009 at 11:49 PM, Jeremy Manson >> > wrote: >> >> As a side note to this conversation, directed at any people who will >> >> think you can't have this feature with this proposal, regardless of >> >> your feelings about the particular merits of accomplishing the same >> >> thing with closures, there *is* a way to handle this case: >> >> >> >> try (LockDisposer l = new LockDisposer(lock.readLock())) { >> >> ?clientCount++; >> >> } >> >> >> >> try (LockDisposer l = new LockDisposer(lock.writeLock())) { >> >> ?return field.getValue(); >> >> } >> > >> > Yow. ?I think the cure might be worse than the disease. >> >> That's why I suggested changing try() so that it took an expression. >> The second version was, I think you will admit, much cleaner. >> >> >> I suspect a LOT of people will be doing something similar to this hack >> >> if this proposal is adopted. ?To make it much cleaner, you could first >> >> adjust this proposal so that the try statement can take an expression >> >> that returns a Disposable, and then you could adjust the Lock classes >> >> so that a) lock() returns this and b) they implement Disposable, at >> >> which point you could have: >> > >> > You can't make such changes to existing interfaces without breaking >> > existing code. ?Changing the signature of lock() breaks existing >> > callers, and adding a close() method (to implement Disposable) breaks >> > existing implementations. >> >> I'm probably being typically dumb, but I'm not sure how adding a >> method breaks anything. You don't *have* to change the signature of >> lock -- just add a new method (call it "disposeLock") that has the >> required semantics: >> >> try (lock.readLock().disposeLock()) { >> ?clientCount++; >> } >> >> try (lock.writeLock().disposeLock()) { >> ?return field.getValue(); >> } >> >> Jeremy >> > > From develop4lasu at gmail.com Wed Mar 4 00:33:30 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Wed, 4 Mar 2009 09:33:30 +0100 Subject: 'This' type In-Reply-To: <49ADAD7E.4090803@sun.com> References: <28bca0ff0903031217q318674a4j29b70b40b7ec80f7@mail.gmail.com> <49ADAD7E.4090803@sun.com> Message-ID: <28bca0ff0903040033x4b487d55r602fcd04e34ab479@mail.gmail.com> 2009/3/3 Joseph D. Darcy > > > 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. > > 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 > Thanks. I'll try to focus on analysis then ;) and bring full analise in time (I just do not have much time now). Refernces: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6479372 http://java.net/cs/user/view/cs_msg/37432 -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Wed Mar 4 01:41:16 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 09:41:16 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <49ADD978.3080804@sun.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> <49ADD978.3080804@sun.com> Message-ID: <200903040941.16335.david.goodenough@linkchoose.co.uk> On Wednesday 04 March 2009, Joseph D. Darcy wrote: > 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. OK, if it will make easier I will change its name. This is a tiny change, and to rule it out because other more invasive ways of approaching the same subject are big and cause problems is just plain daft. This proposal should be evaluated on its own merits. David > > -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 david.goodenough at linkchoose.co.uk Wed Mar 4 01:49:57 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 09:49:57 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <200903032200.28367.david.goodenough@linkchoose.co.uk> <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> Message-ID: <200903040949.57551.david.goodenough@linkchoose.co.uk> I am not sure that we would loose anything. The important thing is to have an IDE/compiler checkable way of generating Property objects, and having two ways of generating them is not really a problem. My Property object would happily detect either an explicitly generated getter/setter or one generated for you by a property keyword. The property keyword would resolve other things (like the automatic generation of PropertyChangeSupport, and the controlling of visibility) but it is still building on the same basic concept. If you don't want to use # then the work needed for the compiler gets more complicated (I think). One could use a sort of compiler function, so one would say property(foo.bar) and it would modify the function of . inside the function. I really want to find a way to get something into Java 7, otherwise we are looking to Java 8 (which is at least 3 years away if current timescales persist), by which time I suspect that everyone will have gotten bored and gone to find pastures new. David On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > But it seems that we _would_ lose a thing or two with this proposal. > For example, if a complete properties proposal supports full backwards > compatibility and generates getters and setters, then we have a bunch > of code around that uses the foo#bar notation, which is by then > already outdated, and would in fact get in the way of using foo#bar > notation as a shorthand for calling the appropriate getter/setter. I > don't know if that is a desired syntax sugar, but the point is: Your > proposal would effectively make it impossible to add that later, as it > would already be shorthand for creating a Property object. > > The # and the backtick are the only easily typed symbols that have no > meaning whatsoever in java right now. Using one up for an simplified > properties proposal is another serious disdvantage. I don't think your > proposal makes property support light enough to warrant its inclusion > in project coin. That's not to say I have something against > properties; on the contrary, I love the idea and I'm very impressed > with the way properties work in JavaFX. All the more reason to get it > right instead of using a bandage. > > --Reinier Zwitserloot > > On Mar 3, 2009, at 23:00, David Goodenough wrote: > > 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 forax at univ-mlv.fr Wed Mar 4 04:58:37 2009 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 04 Mar 2009 13:58:37 +0100 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: <49AE7AFD.7010609@univ-mlv.fr> Joshua Bloch a ?crit : > 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 > There is another way, change the JLS :) In my opinion, the last sentence of section 8.1.5 of the JLS is too restrictive: "A class may not at the same time be a subtype of two interface types which are different invocations of the same generic interface (?9.1.2) , or an invocation of a generic interface and a raw type naming that same generic interface." This sentence is weird because the last part of section 8.1.5 explain how to detect clash between methods from different interfaces by taking a look to their return types. So in case of different interfaces, the compiler have to do a calculation involving the member methods but if interfaces are generics it doesn't do any calculation on member methods. That is not consistent. Note than the detection algorithm is not exactly the same because one can have a clash between bridge methods. I'm proposing to remove the last sentence of section 8.1.5 and replace it by a one saying that if there is of two or more generics super-interfaces, member methods of their raw types should not have the same signature. With theis new rule, the following examples will now compile: interface Duplicate { X duplicate(); } class A implements Duplicate, Duplicate { public Integer duplicate() { return null; } } and interface Disposable { public void dispose() throws E; } class Connection implements Disposable, Disposable { public void dispose() throws IOEXception { } } There is another reason why I don't like the last sentence of section 8.1.5, this sentence is not compatible with section 13.4.4 on binary compatibility: "Changing the direct superclass or the set of direct superinterfaces of a class type will not break compatibility with pre-existing binaries, provided that the total set of superclasses or superinterfaces, respectively, of the class type loses no members." cheers, R?mi From markmahieu at googlemail.com Wed Mar 4 05:36:34 2009 From: markmahieu at googlemail.com (Mark Mahieu) Date: Wed, 4 Mar 2009 13:36:34 +0000 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@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> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> Message-ID: Josh, Yeah, sorry that email was a bit rubbish. It was 3:30am though - please allow me to try again... As you know some resources are allocated and held for much longer than the duration of a single method call, eventually being released on some trigger condition. I'm not suggesting that ARM should try to cater for this, but I do see Neal's point that there's a common desire to pass such resources around or to hold them somewhere, and given that they are often the same *type* in both scenarios, then if ARM introduced the Disposable interface for its purposes, it would be natural for programmers to want to hold the more long-lived ones in a Collection for later disposal. Now, where I was going with my last email was that a library could include an interface that extends Disposable, refining the exception types thrown: interface SWTDisposable extends Disposable { void close() throws SWTException; } The afore-mentioned programmer could now hold a Collection and have much more appropriate exception types to deal with in their cleanup code. (SWTException is unchecked in real life, but the point's the same). If that turned out to be a sensible convention, then the only responsibility for ARM would be to say, in the javadoc for Disposable, "libraries are encouraged to extend this interface, refining the thrown exceptions...". Now, having mentioned SWT... This fairly typical example, from the official SWT 'snippets' page, would benefit very well from the introduction of ARM or some other resource disposal mechanism: http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/ org/eclipse/swt/snippets/Snippet280.java?view=co So if we look at how the SWT library might be retrofitted to work with ARM, we find this class, which is extended by all the various SWT resource classes: public abstract class Resource { /** * Disposes of the operating system resources associated with this resource. */ void dispose() { // ... } // ... } http://help.eclipse.org/stable/nftopic/org.eclipse.platform.doc.isv/ reference/api/org/eclipse/swt/graphics/Resource.html OK, well for once the SWT team's aversion to interfaces has an up- side, and we can easily retrofit this with Disposable, calling dispose () from close(). Or can we? public class Path extends Resource { /** * Closes the current sub path by adding to the receiver a line from the current point of the path back to the starting point of the sub path. */ public void close() { // ... } // ... } http://help.eclipse.org/stable/nftopic/org.eclipse.platform.doc.isv/ reference/api/org/eclipse/swt/graphics/Path.html Square peg, round hole :( Any suggestions? Regards, Mark On 4 Mar 2009, at 03:47, Joshua Bloch wrote: > Mark, > > I don't see a compelling need for it. When in doubt, leave it out. > > Josh > > On Tue, Mar 3, 2009 at 7:39 PM, Mark Mahieu > wrote: > So would APIs be encouraged to define more specific Resource > interfaces that narrow the thrown exception types ... > > interface SQLResource extends Resource { > void dispose() throws SQLException { } > } > > interface SWTResource extends Resource { > void dispose() throws SWTException { } > } > > etc? > > I don't think there'd be any reason to do this. From david.goodenough at linkchoose.co.uk Wed Mar 4 05:38:25 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 13:38:25 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <200903032200.28367.david.goodenough@linkchoose.co.uk> <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> Message-ID: <200903041338.25551.david.goodenough@linkchoose.co.uk> A further thought on the # issue. The . is of course already used in two places, to join an object to its field and to separate fractions from the integer part of a number. The parser can cope with this, so there is no particular reason why it could not cope with other overloading. The test is whether it is obvious to the reader what is going on, and possible for the compiler to tell unambigously which is intended. Just a thought. David On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > But it seems that we _would_ lose a thing or two with this proposal. > For example, if a complete properties proposal supports full backwards > compatibility and generates getters and setters, then we have a bunch > of code around that uses the foo#bar notation, which is by then > already outdated, and would in fact get in the way of using foo#bar > notation as a shorthand for calling the appropriate getter/setter. I > don't know if that is a desired syntax sugar, but the point is: Your > proposal would effectively make it impossible to add that later, as it > would already be shorthand for creating a Property object. > > The # and the backtick are the only easily typed symbols that have no > meaning whatsoever in java right now. Using one up for an simplified > properties proposal is another serious disdvantage. I don't think your > proposal makes property support light enough to warrant its inclusion > in project coin. That's not to say I have something against > properties; on the contrary, I love the idea and I'm very impressed > with the way properties work in JavaFX. All the more reason to get it > right instead of using a bandage. > > --Reinier Zwitserloot > > On Mar 3, 2009, at 23:00, David Goodenough wrote: > > 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 neal at gafter.com Wed Mar 4 06:47:51 2009 From: neal at gafter.com (Neal Gafter) Date: Wed, 4 Mar 2009 06:47:51 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AE7AFD.7010609@univ-mlv.fr> 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> <49AE7AFD.7010609@univ-mlv.fr> Message-ID: <15e8b9d20903040647n4efbfdag9c8191194b7f9899@mail.gmail.com> Remi- Do you have any evidence that this is a sound extension of the type system? -Neal On Wed, Mar 4, 2009 at 4:58 AM, R?mi Forax wrote: > Joshua Bloch a ?crit : >> 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 >> > There is another way, change the JLS :) > > In my opinion, the last sentence of ?section 8.1.5 of the JLS is too > restrictive: > "A class may not at the same time be a subtype of two interface types which > are different invocations of the same generic interface (?9.1.2) > , > or an invocation > of a generic interface and a raw type naming that same generic interface." > > This sentence is weird because the last part of section 8.1.5 explain > how to detect clash between methods from different interfaces > by taking a look to their return types. > > So in case of different interfaces, the compiler have to do a calculation > involving the member methods but if interfaces are generics > it doesn't do any calculation on member methods. > That is not consistent. > > Note than the detection algorithm is not exactly the same because > one can have a clash between bridge methods. > > I'm proposing to remove the last sentence of section 8.1.5 > and replace it by a one saying that if there is of two or more > generics super-interfaces, member methods of their raw types > should not have the same signature. > > With theis new rule, the following examples will now compile: > > interface Duplicate { > ? ? ? X duplicate(); > ? ?} > > class A implements Duplicate, Duplicate { > ? ?public Integer duplicate() { > ? ? ? return null; > ? ?} > ?} > > ? ?and > > ? ?interface Disposable { > ? ? ?public void dispose() throws E; > ? ?} > > ? ?class Connection implements Disposable, > Disposable { > ? ? ?public void dispose() throws IOEXception { > > ? ? ?} > ? ?} > > > There is another reason why I don't like the last sentence of section 8.1.5, > this sentence is not compatible with section 13.4.4 on binary compatibility: > "Changing the direct superclass or the set of direct superinterfaces of > a class type will not break compatibility > with pre-existing binaries, provided that the total set of superclasses > or superinterfaces, > respectively, of the class type loses no members." > > cheers, > R?mi > > > > > From R.Spilker at topdesk.com Wed Mar 4 02:37:19 2009 From: R.Spilker at topdesk.com (=?us-ascii?Q?Roel_Spilker?=) Date: Wed, 4 Mar 2009 11:37:19 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903040949.57551.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> Message-ID: In your proposal, foo#bar would be translated by the compiler into: new Property(foo,"bar"); But I think you should split your proposal into two parts. The first part is using the Foo#bar syntax to be a field literal for the field "bar" in the type "Foo". This is similar to the FCM proposal (http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc). So it would be a java.lang.reflect.Field literal. The second part would be a proposal to build properties using field literals. I give the field literal proposal a chance to be included. Roel -----Oorspronkelijk bericht----- Van: david.goodenough at linkchoose.co.uk [mailto:coin-dev-bounces at openjdk.java.net] Namens David Goodenough Verzonden: woensdag 4 maart 2009 10:50 Aan: coin-dev at openjdk.java.net Onderwerp: Re: PROPOSAL: Lightweight Properties I am not sure that we would loose anything. The important thing is to have an IDE/compiler checkable way of generating Property objects, and having two ways of generating them is not really a problem. My Property object would happily detect either an explicitly generated getter/setter or one generated for you by a property keyword. The property keyword would resolve other things (like the automatic generation of PropertyChangeSupport, and the controlling of visibility) but it is still building on the same basic concept. If you don't want to use # then the work needed for the compiler gets more complicated (I think). One could use a sort of compiler function, so one would say property(foo.bar) and it would modify the function of . inside the function. I really want to find a way to get something into Java 7, otherwise we are looking to Java 8 (which is at least 3 years away if current timescales persist), by which time I suspect that everyone will have gotten bored and gone to find pastures new. David On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > But it seems that we _would_ lose a thing or two with this proposal. > For example, if a complete properties proposal supports full backwards > compatibility and generates getters and setters, then we have a bunch > of code around that uses the foo#bar notation, which is by then > already outdated, and would in fact get in the way of using foo#bar > notation as a shorthand for calling the appropriate getter/setter. I > don't know if that is a desired syntax sugar, but the point is: Your > proposal would effectively make it impossible to add that later, as it > would already be shorthand for creating a Property object. > > The # and the backtick are the only easily typed symbols that have no > meaning whatsoever in java right now. Using one up for an simplified > properties proposal is another serious disdvantage. I don't think your > proposal makes property support light enough to warrant its inclusion > in project coin. That's not to say I have something against > properties; on the contrary, I love the idea and I'm very impressed > with the way properties work in JavaFX. All the more reason to get it > right instead of using a bandage. > > --Reinier Zwitserloot > > On Mar 3, 2009, at 23:00, David Goodenough wrote: > > 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 Joe.Darcy at Sun.COM Wed Mar 4 07:00:12 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 07:00:12 -0800 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903040941.16335.david.goodenough@linkchoose.co.uk> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <15e8b9d20903031217n632eae0el7ee9cfafdb0c504@mail.gmail.com> <49ADD978.3080804@sun.com> <200903040941.16335.david.goodenough@linkchoose.co.uk> Message-ID: <49AE977C.8040907@sun.com> David Goodenough wrote: > On Wednesday 04 March 2009, Joseph D. Darcy wrote: > >> 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. >> > > OK, if it will make easier I will change its name. Changing the proposal's name doesn't change what it is! -Joe From forax at univ-mlv.fr Wed Mar 4 07:22:16 2009 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 04 Mar 2009 16:22:16 +0100 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20903040647n4efbfdag9c8191194b7f9899@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> <49AE7AFD.7010609@univ-mlv.fr> <15e8b9d20903040647n4efbfdag9c8191194b7f9899@mail.gmail.com> Message-ID: <49AE9CA8.5020202@univ-mlv.fr> Neal Gafter a ?crit : > Remi- > > Do you have any evidence that this is a sound extension of the type system? > I don't think the rule about generics interfaces is here to ensure that the type system is sound or not. It's about avoiding clash between bridges that as you know contains code. R?mi From david.goodenough at linkchoose.co.uk Wed Mar 4 07:35:51 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 15:35:51 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> Message-ID: <200903041535.53432.david.goodenough@linkchoose.co.uk> On Wednesday 04 March 2009, Roel Spilker wrote: > In your proposal, foo#bar would be translated by the compiler into: new > Property(foo,"bar"); > > But I think you should split your proposal into two parts. The first part > is using the Foo#bar syntax to be a field literal for the field "bar" in > the type "Foo". This is similar to the FCM proposal > (http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc). So it would be a > java.lang.reflect.Field literal. > > The second part would be a proposal to build properties using field > literals. > > I give the field literal proposal a chance to be included. > > Roel > I would not be unhappy with that, if were it possible. But I think that due to the way that Field objects are represented in the class file (in an odd binary format) and then constructed at run time, that this would not be possible. It is important (for things like accessing Annotations) that we get the REAL Field object, and not a partial copy or lookalike. If someone can come up with a way of doing that I would be delighted. David > > > -----Oorspronkelijk bericht----- > Van: david.goodenough at linkchoose.co.uk > [mailto:coin-dev-bounces at openjdk.java.net] Namens David Goodenough > Verzonden: woensdag 4 maart 2009 10:50 > Aan: coin-dev at openjdk.java.net > Onderwerp: Re: PROPOSAL: Lightweight Properties > > I am not sure that we would loose anything. The important thing is to have > an IDE/compiler checkable way of generating Property objects, and having > two ways of generating them is not really a problem. My Property object > would happily detect either an explicitly generated getter/setter or one > generated for you by a property keyword. The property keyword would > resolve other things (like the automatic generation of > PropertyChangeSupport, and the controlling of visibility) but it is still > building on the same basic concept. > > If you don't want to use # then the work needed for the compiler gets more > complicated (I think). One could use a sort of compiler function, so one > would say property(foo.bar) and it would modify the function of . inside > the function. > > I really want to find a way to get something into Java 7, otherwise we are > looking to Java 8 (which is at least 3 years away if current timescales > persist), by which time I suspect that everyone will have gotten bored and > gone to find pastures new. > > David > > On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > > But it seems that we _would_ lose a thing or two with this proposal. > > For example, if a complete properties proposal supports full backwards > > compatibility and generates getters and setters, then we have a bunch > > of code around that uses the foo#bar notation, which is by then > > already outdated, and would in fact get in the way of using foo#bar > > notation as a shorthand for calling the appropriate getter/setter. I > > don't know if that is a desired syntax sugar, but the point is: Your > > proposal would effectively make it impossible to add that later, as it > > would already be shorthand for creating a Property object. > > > > The # and the backtick are the only easily typed symbols that have no > > meaning whatsoever in java right now. Using one up for an simplified > > properties proposal is another serious disdvantage. I don't think your > > proposal makes property support light enough to warrant its inclusion > > in project coin. That's not to say I have something against > > properties; on the contrary, I love the idea and I'm very impressed > > with the way properties work in JavaFX. All the more reason to get it > > right instead of using a bandage. > > > > --Reinier Zwitserloot > > > > On Mar 3, 2009, at 23:00, David Goodenough wrote: > > > 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 david.goodenough at linkchoose.co.uk Wed Mar 4 07:55:43 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 15:55:43 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <49AE977C.8040907@sun.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <200903040941.16335.david.goodenough@linkchoose.co.uk> <49AE977C.8040907@sun.com> Message-ID: <200903041555.46210.david.goodenough@linkchoose.co.uk> On Wednesday 04 March 2009, Joseph D. Darcy wrote: > David Goodenough wrote: > > On Wednesday 04 March 2009, Joseph D. Darcy wrote: > >> 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. > > > > OK, if it will make easier I will change its name. > > Changing the proposal's name doesn't change what it is! > > -Joe Yes, well to quote your blog entry:- >Properties: While a detailed judgment would have to be made against a >specific proposal, as a new kind of type properties would most likely be at >least medium-sized. This one is very small (at least compared to some of the others I see in the list). So a detailed judgement needs to made against this specific proposal. This proposal is an attempt to get the core of the problem, to strip away much that has been added to existing proposals, and to solve the problems that any Beans Binding framework and APIs like the JPA Criteria API have and that can currently only be solved by using String field names which can not reasonably be checked by a compiler/IDE. I would suggest that one of Java's greatest strengths is its checkability, and the lack of this simple proposal (or something like it) drives a coach and horses through that strength leaving it not much better than a scripting language. David From develop4lasu at gmail.com Wed Mar 4 09:06:02 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Wed, 4 Mar 2009 18:06:02 +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: <28bca0ff0903040906q15bb6265hd849372ab8b84892@mail.gmail.com> Hi. I do not know if I understand you right. MAJOR DISADVANTAGE: - Property names can be dropped (methods not). - Linking naming with code logics. Other proposal that may make yours one unnecessarily: add @ operator (or ^) method@ would return Method object for given method. field@ would return Field object for given field. - This should allow u to write classes u need and make language almost 100% as it is. - It would be faster. - Independend from names. I might be wrong so tell me if I missed something. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Wed Mar 4 09:31:16 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Wed, 4 Mar 2009 17:31:16 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <28bca0ff0903040906q15bb6265hd849372ab8b84892@mail.gmail.com> References: <200903031459.03331.david.goodenough@linkchoose.co.uk> <28bca0ff0903040906q15bb6265hd849372ab8b84892@mail.gmail.com> Message-ID: <200903041731.18231.david.goodenough@linkchoose.co.uk> On Wednesday 04 March 2009, Marek Kozie? wrote: > Hi. > > I do not know if I understand you right. > > MAJOR DISADVANTAGE: > - Property names can be dropped (methods not). > - Linking naming with code logics. > > Other proposal that may make yours one unnecessarily: > > add @ operator (or ^) > method@ would return Method object for given method. > field@ would return Field object for given field. > > - This should allow u to write classes u need and make language almost 100% > as it is. > - It would be faster. > - Independend from names. > > I might be wrong so tell me if I missed something. I have no problem in extending this to Methods. I just do not have a need for extending it to Methods so I have not considered it. I also have no problem with simplifying my proposal to generate Field objects, were it possible which I have my doubts about. The problem with getting Field and Method objects is that you need to be sure that you get the real Field or Method object, and that is difficult as I see it as a result of the way that Field and Method data is stored in class files. They are stored in a binary format and then real Field and Method objects are generated at run time. Correlating that process with the code that the compiler would generate is (I think - please someone prove me wrong) difficult. It is important that we get to the real Field and Method objects for two reasons. Firstly this mechanism can also be used to find Annotations, which is something currently lacking from the PropertyDescriptor support which returns the Class of the return object from the getter not the Class of the field which means you can not find its annotations. The second problem is that we might want to use the Field object to correlate with the parent object. We can scan the Field array from an object very easily, and I am not quite sure I know the checks that a .equals method would have to do to establish equality when reference identity would do. David From Alex.Buckley at Sun.COM Wed Mar 4 09:59:17 2009 From: Alex.Buckley at Sun.COM (Alex Buckley) Date: Wed, 04 Mar 2009 09:59:17 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AE9CA8.5020202@univ-mlv.fr> 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> <49AE7AFD.7010609@univ-mlv.fr> <15e8b9d20903040647n4efbfdag9c8191194b7f9899@mail.gmail.com> <49AE9CA8.5020202@univ-mlv.fr> Message-ID: <49AEC175.2050804@sun.com> R?mi Forax wrote: > Neal Gafter a ?crit : >> Remi- >> >> Do you have any evidence that this is a sound extension of the type >> system? >> > I don't think the rule about generics interfaces is here to ensure that > the type system is sound or not. > It's about avoiding clash between bridges that as you know contains code. As fully explained at http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ401 What would you do about bridge methods in the example there? In fact, don't tell me. Either file a Request For Enhancement against JLS 8.1.5, or fill in the proposal form and send it to coin-dev. Don't take the ARM proposal discussion off-topic. Alex From jjb at google.com Wed Mar 4 11:09:22 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 11:09:22 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> Message-ID: <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> Mark, Hello again. On Wed, Mar 4, 2009 at 5:36 AM, Mark Mahieu wrote: > > > Now, where I was going with my last email was that a library could include > an interface that extends Disposable, refining the exception types thrown: > > interface SWTDisposable extends Disposable { > void close() throws SWTException; > } > > The afore-mentioned programmer could now hold a Collection > and have much more appropriate exception types to deal with in their cleanup > code. (SWTException is unchecked in real life, but the point's the same). > Seems harmless. This could also be be retrofitted: a class could implement Disposable, and then be retrofitted to implement SWTDisposable in a later release. My natural inclination would be to do this only where there was a clear need, and do it on a case-by-case basis as the need arose. > > OK, well for once the SWT team's aversion to interfaces has an up-side, and > we can easily retrofit this with Disposable, calling dispose() from close(). > Or can we? > > public class Path extends Resource { > > /** > * Closes the current sub path by adding to the receiver a line from the > current point of the path back to the starting point of the sub path. > */ > public void close() { > // ... > } > > // ... > } > > > http://help.eclipse.org/stable/nftopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/Path.html > Yep. This was bound to happen:( That's why Tim Peierls favored the use of an annotation to mark the "disposal method." But Mark Reinhold has made it clear that this would (still) be unacceptable to Sun: annotations must not change semantics. So be it. This problem is one of those unfortunate things that happen when you retrofit a feature after a platform has been around for over a decade:( I think the solution must necessarily be a bit hackish. Here's one possibility, based loosely on the way for-each works. A resource can implement one of several interfaces. One (currently named Disposable) contains a close method. Another (name tbd) contains a dispose method. A third might contain a destroy method. I can't imagine an existing type to which none of these three interfaces can be retrofitted. The SWT Resource type could be retrofitted to implement the interface with the dispose method, without even adding a new method. This isn't beautiful, but it works. I think it's probably a good idea. Thanks for all the sleuthing, Josh From thorsten at vanellen.de Wed Mar 4 12:09:35 2009 From: thorsten at vanellen.de (Thorsten van Ellen) Date: Wed, 04 Mar 2009 21:09:35 +0100 Subject: Idea for Language Extensions for Interface-Protocols, was Re: Automatic Resource Management and Simple Resource Clean-up In-Reply-To: <49AD9EBE.5010808@vanellen.de> References: <49AD9EBE.5010808@vanellen.de> Message-ID: <49AEDFFF.5080101@vanellen.de> By the way: * allocate - deallocate * open - close * begin - commit/rollback * lock - unlock * push - push - pop - pop and so on, all have somthing in common and that is: a protocol on top of the signature. Expressing protocols for interfaces might be a great language feature and solving many more bugs caused by misused interfaces than only misused resources. But surely it is a complex feature. Protocols itself could be expressed with their own languages, e.g., simple regular expressions or even more complex expressions. Languages that can be evaluated at compile time, e.g., for simple cases like "open - close" and languages that have to trace a state to be evaluated at runtime, e.g., "push - push - pop - pop". Compile time mechanisms can not easily be developed by individuals. Runtime mechanisms could be developed individually without language extensions but need effort for every single case. Language extensions like regular expressions could solve the problem generally with one runtime mechanism. Some of them could also be expressed by design by contract which is also a complex feature probably even more complex, but that only works at runtime and does not find errors at compile time. It is only one idea, no proposal, probably too complex for this project and therefore offtopic. Best regards Thorsten van Ellen From scolebourne at joda.org Wed Mar 4 13:32:51 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 04 Mar 2009 21:32:51 +0000 Subject: PROPOSAL: Static Methods in Interfaces In-Reply-To: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> References: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> Message-ID: <49AEF383.2000607@joda.org> Reinier Zwitserloot wrote: > MAJOR DISADVANTAGE: > > No opportunity to use the static > keyword in interfaces for some sort of factory interface concept (an > interface for constructors and static methods). I think this is a key one, as it limits future Java changes. I'd like to see Java support 'static implements': public class Foo implements Bar, static Baz { ... } where any methods defined by Baz have to be implemented by Foo as static methods. > 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. I don't consider the utils class to be a particularly bad alternative. > 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. Making these changes would appear to be backwards incompatible if the implementing class already defines the method added to the interface. Stephen From markmahieu at googlemail.com Wed Mar 4 13:45:26 2009 From: markmahieu at googlemail.com (Mark Mahieu) Date: Wed, 4 Mar 2009 21:45:26 +0000 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031722h627831baj5913653729949592@mail.gmail.com> <17b2302a0903031747o1c5049d0ncac56a00815ed348@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> Message-ID: <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> Josh, On 4 Mar 2009, at 19:09, Joshua Bloch wrote: > I think the solution must necessarily be a bit hackish. Here's > one possibility, based loosely on the way for-each works. A > resource can implement one of several interfaces. One (currently > named Disposable) contains a close method. Another (name tbd) > contains a dispose method. A third might contain a destroy > method. I can't imagine an existing type to which none of these > three interfaces can be retrofitted. The SWT Resource type could > be retrofitted to implement the interface with the dispose method, > without even adding a new method. This isn't beautiful, but it > works. I think it's probably a good idea. Well, since we probably can't iron out every inconsistency with what's gone before, we could try to be consistently ironic: interface Disposable { void close() throws Exception; } interface Destroyable { void dispose() throws Exception; } interface Kloseable { void destroy() throws Exception; } ;) In all seriousness, what should the behaviour then be if a class implements two or more of these interfaces? Should all of the 'disposal' methods be invoked? Putting interfaces aside for a moment, instead of an annotation my instinct would have been to reach for a modifier here, especially given that this proposal is for dedicated language support rather than a library based solution. There's even one reserved word already that conveys the meaning pretty well: class SomeResourceType { public finally void release() { // ... } } That approach may well raise all sorts of questions as well - I can certainly think of a couple - but compared to using an annotation, what's wrong with it? Mark From forax at univ-mlv.fr Wed Mar 4 13:48:27 2009 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 04 Mar 2009 22:48:27 +0100 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AEC175.2050804@sun.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> <49AE7AFD.7010609@univ-mlv.fr> <15e8b9d20903040647n4efbfdag9c8191194b7f9899@mail.gmail.com> <49AE9CA8.5020202@univ-mlv.fr> <49AEC175.2050804@sun.com> Message-ID: <49AEF72B.8070807@univ-mlv.fr> Alex Buckley a ?crit : > R?mi Forax wrote: >> Neal Gafter a ?crit : >>> Remi- >>> >>> Do you have any evidence that this is a sound extension of the type >>> system? >>> >> I don't think the rule about generics interfaces is here to ensure >> that the type system is sound or not. >> It's about avoiding clash between bridges that as you know contains >> code. > > As fully explained at > http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ401 > > > What would you do about bridge methods in the example there? > > In fact, don't tell me. Either file a Request For Enhancement against > JLS 8.1.5, or fill in the proposal form and send it to coin-dev. Don't > take the ARM proposal discussion off-topic. > > Alex Hi Alex, I was not trying to hijack the ARM proposal discussion but just saying that interface Disposable can be a generics. R?mi From jjb at google.com Wed Mar 4 14:17:33 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 14:17:33 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> Message-ID: <17b2302a0903041417t15b0c8bck5a3d5c27e4b51103@mail.gmail.com> Mark, On Wed, Mar 4, 2009 at 1:45 PM, Mark Mahieu wrote: > > > In all seriousness, what should the behaviour then be if a class implements > two or more of these interfaces? Should all of the 'disposal' methods be > invoked? > I'd make it a compile-time error to use an automatic resource management statement if the static type is a subtype of more than one of these interfaces. > > Putting interfaces aside for a moment, instead of an annotation my instinct > would have been to reach for a modifier here, > That's a possibility too. Josh From reinier at zwitserloot.com Wed Mar 4 14:35:46 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 4 Mar 2009 23:35:46 +0100 Subject: PROPOSAL: Static Methods in Interfaces In-Reply-To: <49AEF383.2000607@joda.org> References: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> <49AEF383.2000607@joda.org> Message-ID: <02EC68D8-E2D4-4250-9139-14D50F5E3E75@zwitserloot.com> Hey Stephen, Answers inline. Summary: 1. This proposal does not preclude future 'static implements' concepts. Because of similar terminology there might be more confusion, is all. 2. No, you're mistaken, there is no backwards incompatibility. --Reinier Zwitserloot On Mar 4, 2009, at 22:32, Stephen Colebourne wrote: > Reinier Zwitserloot wrote: >> MAJOR DISADVANTAGE: >> >> No opportunity to use the static >> keyword in interfaces for some sort of factory interface concept (an >> interface for constructors and static methods). > > I think this is a key one, as it limits future Java changes. I'd > like to > see Java support 'static implements': I'd like that as well, but it's not a key disadvantage. There are plenty of ways to make that happen even if static methods are allowed in interfaces. The only disadvantage here is that the existence of this feature, as well as a static implements feature, can be slightly more confusing that either one on its own. Two rough sketches of static implements features that don't conflict with the Static Methods in Interfaces proposal: //separate interfaces from static-implements type interfaces entirely. public factory interface Foo { public static void someMethod(); } or: //use the 'abstract' keyword. public interface Foo { public abstract static void someMethod(); } Either of those approaches would be fine. > > I don't consider the utils class to be a particularly bad alternative. I do. If there is a method that does useful things to Lists, provided by the author(s) of the List interface, then it should be in List, or at the very least, it should be possible to link the ListUtils class to the List interface via something that IDEs will universally recognize. If you'd like to propose a way to do that instead, for example with an annotation, I could live with that as well, though such a proposal would not cater as nicely to the 'other languages on the JVM' crowd, and would not result in code that is as elegant. (I consider List.of(foo, bar); a lot cleaner than ListUtils.of(foo, bar);, but perhaps one can't argue taste). > > Making these changes would appear to be backwards incompatible if the > implementing class already defines the method added to the interface. I don't think it would be, because, as the proposal mentions, static methods in interfaces do NOT inherit. So, If List.java did have a static of method, then trying: ArrayList.of(foo, bar); would not be legal (method not found). So, if someone has rolled their own List implementation that so happens to have a static of method, then there's no problem at all: List.of(); //finds List's of. MyOwnListImpl.of(); //finds your own of(). If of() isn't a static method, there is still no problem. The proposal outlines that static calls via an instance aren't allowed either, so: List x = new MyOwnListImpl(); x.of(); //wouldn't find EITHER method. It won't find List.of() because you can't invoke static methods on interfaces via an instance, and it won't find your own home-grown of for the same reason you won't be allowed to call intValue() on a variable of type Object that just so happens to hold an Integer instance). If I'm mistaken, please outline an example of a collision so I can add a relevant paragraph in the 'compatibilities' section, but I don't think there is one. It's one of the reasons why the proposal contains the caveat that static methods in interfaces do not inherit at all. > From tim at peierls.net Wed Mar 4 14:40:16 2009 From: tim at peierls.net (Tim Peierls) Date: Wed, 4 Mar 2009 17:40:16 -0500 Subject: Proposal: Automatic Resource Management In-Reply-To: <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20903031808n1e75986ch4e58d9ed51dfc25c@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> Message-ID: <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> I've never understood the fervor with which Java is defended from annotations that can change program semantics; the defenders' arguments always sound suspiciously circular. But never mind that ... I confess that even though I would have been happy with @Finally public void release() { ... } I'd much prefer public finally void release() { ... } If, as I fear, neither of these are ultimately found palatable, then Disposable.close() may have to do -- it might be restricted to solving a smaller problem than I'd hoped, but that's still an important problem to solve. --tim On Wed, Mar 4, 2009 at 4:45 PM, Mark Mahieu wrote: > Putting interfaces aside for a moment, instead of an annotation my > instinct would have been to reach for a modifier here, especially > given that this proposal is for dedicated language support rather > than a library based solution. There's even one reserved word > already that conveys the meaning pretty well: > > class SomeResourceType { > > public finally void release() { > // ... > } > } > > > That approach may well raise all sorts of questions as well - I can > certainly think of a couple - but compared to using an annotation, > what's wrong with it? From Joe.Darcy at Sun.COM Wed Mar 4 15:08:03 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 15:08:03 -0800 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: <49AF09D3.7050506@sun.com> 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. > Okay. >>> 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? > Yes; effectively sets of exception types are being computed and operated on; it would help clarify some of hter interactions for me to see some worked examples. >>> 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. > Without the final rethrow, do actual disjunctive types need to be added to support multi-catch? Thanks, -Joe From Joe.Darcy at Sun.COM Wed Mar 4 15:11:55 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 15:11:55 -0800 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <15e8b9d20903030704j4fbf2f31if64f59b381c8864f@mail.gmail.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> <15e8b9d20903030704j4fbf2f31if64f59b381c8864f@mail.gmail.com> Message-ID: <49AF0ABB.20104@sun.com> Hello. I'd prefer to see this listed as an alternative in the next iteration of the Improved Exception Handling draft to the problem of source incompatibility, an incompatibility we might be able to live with anyway. I think a general foreign interoperability proposal while interesting, would be outside the focus of Project Coin. -Joe Neal Gafter wrote: > 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 jjb at google.com Wed Mar 4 15:17:28 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 15:17:28 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> Message-ID: <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> Tim, Hi! On Wed, Mar 4, 2009 at 2:40 PM, Tim Peierls wrote: > I've never understood the fervor with which Java is defended from > annotations that can change program semantics; the defenders' arguments > always sound suspiciously circular. But never mind that ... I confess that > even though I would have been happy with > > @Finally public void release() { ... } > > I'd much prefer > > public finally void release() { ... } > I think it's worth adding this to the proposal as a design alternative. The finally modifier could appear on one and only one method. It would have to be a public, parameterless instance method. This would require a (small) class file format change, and a change to the JavaDoc tool, which would document that the class was a "resource," and which method was its disposal method. It would make the automatic resource management statement a bit more broadly applicable at the expense of a bit of added complexity. Josh > From Joe.Darcy at Sun.COM Wed Mar 4 15:28:20 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 15:28:20 -0800 Subject: (update) Use "default" keyword for default visibility In-Reply-To: <43577BD5-8BD8-45F0-B190-EB04FBB283C3@iam.unibe.ch> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <49AD1C0B.3070907@joda.org> <43577BD5-8BD8-45F0-B190-EB04FBB283C3@iam.unibe.ch> Message-ID: <49AF0E94.6000206@sun.com> Hello. While the lack of an explicit name for the default accessibility in Java has slightly annoyed me at times over the years, I don't think it in isolation is such a troublesome issue that a language change is warranted. A few comments inline... Adrian Kuhn wrote: > 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). > Not all modifiers are applicable in all places. For example, "private" cannot appear on the methods of an interface. A more convincing specification would list explicitly the grammar changes and updated JLS sections. > 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. That would be a non-starter if mandatory; it would mean gratuitous source incompatibilities between JDK 7 and earlier source levels. An annotation processor can be written to do this to enforce local coding conventions. -Joe > 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 Joe.Darcy at Sun.COM Wed Mar 4 15:39:00 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 15:39:00 -0800 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: References: Message-ID: <49AF1114.3080205@sun.com> Greetings. Static import was surprising complicated in JDK 5. While these aliases could alleviate some problems, I think they would be easily abused and even when not being abused render code less readable. 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. > IMO, having alternate names for potentially common classes would be less readable. > 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. > While grammar changes are part of the picture, the substantive changes would be to JLSv3 section 6.5 "Determining the Meaning of a Name": http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.5 -Joe > 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 scolebourne at joda.org Wed Mar 4 15:54:49 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 04 Mar 2009 23:54:49 +0000 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> Message-ID: <49AF14C9.3050309@joda.org> > interface Disposable { > void close() throws Exception; > } > interface Destroyable { > void dispose() throws Exception; > } > interface Kloseable { > void destroy() throws Exception; > } Er, no. If its to be an interface it needs to be just one. A single interface - Disposable defining close() covers most use cases, and API writers would adapt in the future. > public finally void release() { ... } I think this works well, and opens up more options. Are there any specific grammer objections? It would be possible to add a marker interface Finally which enforces the presence of the finally modifier, but that seems to have little obvious benefit, and be a bit magical. Stephen From jjb at google.com Wed Mar 4 16:37:41 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 16:37:41 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AF14C9.3050309@joda.org> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> <49AF14C9.3050309@joda.org> Message-ID: <17b2302a0903041637j77268621n483f10cabca929cc@mail.gmail.com> It is perhaps worth reiterating that the "finally" (or other keyword) solution really does make things more complex. We'd need to add rules like this: A class is a resource iff it has a method that is labeled finally. The superclass of a resource must not be a resource. The finally modifier must not be used on an interface method. We'd need to decide which bit is to be set in the class file to indicate that a method has the finally modifier (luckily there are 6 available). We'd need to decide whether a bit should be set on the resource class, and if so, which bit. It would be redundant to set such a bit, but it would allow the compiler and the VM to quickly determine whether a class was a resource. We'd have to modify JavaDoc. And so on. In the absence of this addition, the proposal really is a simple AST transformation. I'm not arguing that we shouldn't do the "finally" (or other keyword) thing, but that we should only do it if we decide that the added breadth of applicability is worth the added complexity. Remember that Coin means "small change";) Josh On Wed, Mar 4, 2009 at 3:54 PM, Stephen Colebourne wrote: > > interface Disposable { > > void close() throws Exception; > > } > > interface Destroyable { > > void dispose() throws Exception; > > } > > interface Kloseable { > > void destroy() throws Exception; > > } > > Er, no. If its to be an interface it needs to be just one. > > A single interface - Disposable defining close() covers most use cases, > and API writers would adapt in the future. > > > public finally void release() { ... } > > I think this works well, and opens up more options. Are there any > specific grammer objections? > > It would be possible to add a marker interface Finally which enforces > the presence of the finally modifier, but that seems to have little > obvious benefit, and be a bit magical. > > Stephen > > From jodastephen at gmail.com Wed Mar 4 15:59:24 2009 From: jodastephen at gmail.com (Stephen Colebourne) Date: Wed, 04 Mar 2009 23:59:24 +0000 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: <49AF1114.3080205@sun.com> References: <49AF1114.3080205@sun.com> Message-ID: <49AF15DC.20408@gmail.com> Joseph D. Darcy wrote: > IMO, having alternate names for potentially common classes would be less > readable. > The Javapolis discussions of 2007 ended with the majority of participants choosing against aliasing of imports (typedefs). http://www.javapolis.com/confluence/plugins/advanced/gallery-slideshow.action?pageId=32793&decorator=popup&imageNumber=9 Stephen From akuhn at iam.unibe.ch Wed Mar 4 16:43:42 2009 From: akuhn at iam.unibe.ch (Adrian Kuhn) Date: Thu, 5 Mar 2009 01:43:42 +0100 Subject: (update) Use "default" keyword for default visibility In-Reply-To: <49AF0E94.6000206@sun.com> References: <8EAFB4E0-5A40-4E09-810B-803BAE598335@iam.unibe.ch> <49AD1C0B.3070907@joda.org> <43577BD5-8BD8-45F0-B190-EB04FBB283C3@iam.unibe.ch> <49AF0E94.6000206@sun.com> Message-ID: On Mar 5, 2009, at 00:28 , Joseph D. Darcy wrote: > Not all modifiers are applicable in all places. For example, > "private" cannot appear on the methods of an interface. A more > convincing specification would list explicitly the grammar changes > and updated JLS sections. That's feels like writing up house rules for D&D :) Changes to http://java.sun.com/docs/books/jls/download/langspec-3.0.pdf 6 [..] The default access is that a member can be accessed anywhere within the package that contains its declaration; other possibilities are public, protected, and private. [* Actually, this is not true for interface members and enum constructors! The introduction of the chapters seems to be prose anyway, so I dont fix that for now. ] 6.6.1 second item - [...] If a top level class or interface type is declared "package" or has no access modifier, then it may be accessed only from within the package in which it is declared. 6.6.1 last item - Otherwise, if the member or constructor is declared "package" or has no access modifier, then access is permitted only when it occurs from within the package in which the type is declared. 6.6.4 If a class lacks the public modifier or is declared "package", access to the class declaration is limited to the package in which it is declared (?6.6). [* Example may need to be updated.] 6.6.5 If the "package" modifier is specified or none of the access modifiers are specified, [..] If a public class has a method or constructor with default access or "package" modifier, then this method or constructor is not accessible to or inherited by a subclass declared outside this package. [* Example may need to be updated.] 8 Field, method, member class, member interface, and constructor declarations may include the access modifiers (?6.6) package, public, protected, or private. 8.1.1 /ClassModifier: one of/ /Annotation/ package public protected private abstract static final strictfp [* I could not find a sentence that declares multiple access modifiers to be a compile-time error. Where is this stated for classes if not here?] 8.2.1.1 [* Example may need to be updated.] 8.3.1 /FieldModifier: one of/ /Annotation/ package public protected private static final transient volatile A compile-time error occurs [..] if a field declaration has more than one of the access modifiers package, public, protected, and private. 8.4.3 /MethodModifier: one of/ /Annotation/ package public protected private abstract static final synchronized native strictfp A compile-time error occurs [..] if a method declaration has more than one of the access modifiers package, public, protected, and private. 8.4.8 [..] of the superclass and superinterfaces that are public, protected, "package" or declared with default access in the same package as C and [..] [...] - /m2/ is public, protected, package or declared with default access in the same package as C, or [...] 8.4.8.4 If the overridden or hidden method is "package" or has default access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs. 8.5.1 The access modifiers package, public, protected, and private are discussed in ?6.6. A compile-time error occurs if a member type declaration has more than one of the access modifiers package, public, protected, and private. 8.8.3 /ConstructorModifier: one of/ /Annotation/ package public protected private The access modifiers package, public, protected, and private are discussed in ?6.6. A compile-time error occurs [..] if a constructor declaration has more than one of the access modifiers package, public, protected, and private. It is a compile-time error if the constructor of an enum type (?8.9) is declared package, public or protected. [* BTW, another irregularity here: for enum constructors, no access modifier means private not default access. This may violate the principle of least surprise. ] 8.8.9 5th paragraph [..] otherwise, if the class is declared "package" or has no access modifier, the default constructor is implicitly given the access modifier "package". 9.1.1 /InterfaceModifier: one of/ /Annotation/ package public protected private abstract static strictfp [* Again, I could not find a sentence that declares multiple access modifiers to be a compile-time error. Where is this stated for interfaces if not here?] 9.3 [* Would need a change if we want to allow interfaces members to be package visible. See Alex Buckley's blog posts. Currently, if interface members do have no access modifiers, they are assumed to be public. ] 9.4 [* Same as above.] 12.3.3 first item [..] because the field or method was declared private, protected, "package", or default access (not public), or because the class was not declared public. 13.4.7 [..] Less access is permitted if the access modifier is changed from "package" access to private access; from protected access to "package" or privat access; or from public access to protected, "package", or private access. [..] 14.3 It is a compile-time error if a local class declaration contains any one of the following access modifiers: package, public, protected, private, or static. [* Is this correct? I guess, since no access modifier on local class means local visibility not default visibility. ] 18.1 /Modifier:/ /Annotation/ package public protected ... >> 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. > > That would be a non-starter if mandatory; it would mean gratuitous > source incompatibilities between JDK 7 and earlier source levels. > An annotation processor can be written to do this to enforce local > coding conventions. Okay, dropped. cheers, AA From neal at gafter.com Wed Mar 4 18:31:26 2009 From: neal at gafter.com (Neal Gafter) Date: Wed, 4 Mar 2009 18:31:26 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AF14C9.3050309@joda.org> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> <49AF14C9.3050309@joda.org> Message-ID: <15e8b9d20903041831r2a2eb289pbefd4a3b27edec62@mail.gmail.com> On Wed, Mar 4, 2009 at 3:54 PM, Stephen Colebourne wrote: >> public finally void release() { ... } > > I think this works well, and opens up more options. Are there any > specific grammer objections? Having both final and finally as modifiers will be confusing. From mr at sun.com Wed Mar 4 19:35:41 2009 From: mr at sun.com (Mark Reinhold) Date: Wed, 04 Mar 2009 19:35:41 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: jjb@google.com; Wed, 04 Mar 2009 16:37:41 PST; <17b2302a0903041637j77268621n483f10cabca929cc@mail.gmail.com> Message-ID: <20090305033541.B4CF2D06B@callebaut.niobe.net> > Date: Wed, 04 Mar 2009 16:37:41 -0800 > From: Joshua Bloch > It is perhaps worth reiterating that the "finally" (or other keyword) > solution really does make things more complex. Yes, but the complexity might be worthwhile. On the surface, at least, doing this in the language makes a lot more sense to me than doing it with an interface. There are numerous subtleties, no doubt, but this idea seems worth further investigation. > We'd need to add rules like > this: A class is a resource iff it has a method that is labeled finally. That's not so hard. > The superclass of a resource must not be a resource. Not clear. We could, e.g., allow a superclass to be a resource so long as the subclass does not override the disposal method, or if it does override it then it must declare that exact same method "finally". > The finally modifier > must not be used on an interface method. Yes. By analogy with "synchronized" one could say that "finally" just doesn't belong in an interface. This also avoids clashes in the case of a class that implements two interfaces, each of which declares a different disposal method. > We'd need to decide which bit is > to be set in the class file to indicate that a method has the finally > modifier (luckily there are 6 available). We'd need to decide whether a bit > should be set on the resource class, and if so, which bit. It would be > redundant to set such a bit, but it would allow the compiler and the VM to > quickly determine whether a class was a resource. We'd have to modify > JavaDoc. These are all perfectly valid concerns, but I don't think the answers are necessarily all that hard. > And so on. In the absence of this addition, the proposal really is > a simple AST transformation. I'm not arguing that we shouldn't do > the "finally" (or other keyword) thing, but that we should only do it if we > decide that the added breadth of applicability is worth the added > complexity. Remember that Coin means "small change";) Indeed. Joe might disagree, but to my eye a worked-out proposal for keyword-based disposal methods could still meet the threshold of "small change". - Mark From jjb at google.com Wed Mar 4 19:54:47 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 19:54:47 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <20090305033541.B4CF2D06B@callebaut.niobe.net> References: <17b2302a0903041637j77268621n483f10cabca929cc@mail.gmail.com> <20090305033541.B4CF2D06B@callebaut.niobe.net> Message-ID: <17b2302a0903041954i7fcb6423j4e7f779285cd53b3@mail.gmail.com> Mark, Hi. On Wed, Mar 4, 2009 at 7:35 PM, Mark Reinhold wrote: > > Date: Wed, 04 Mar 2009 16:37:41 -0800 > > From: Joshua Bloch > > > It is perhaps worth reiterating that the "finally" (or other keyword) > > solution really does make things more complex. > > Yes, but the complexity might be worthwhile. Agreed. I wasn't saying that we shouldn't do it; just that we should only do it with our eyes open. > On the surface, at least, > doing this in the language makes a lot more sense to me than doing it > with an interface. On the one hand, we did for-each with an interface. But on the other that was targeted at a more limited set of types, and it was no real hardship that the method that they had to implement Iterable. > > > The superclass of a resource must not be a resource. > > Not clear. We could, e.g., allow a superclass to be a resource so long > as the subclass does not override the disposal method, Yep. That's what I meant to say, but now what I said. Oops;) > > > Remember that Coin means "small change";) > > Indeed. Joe might disagree, but to my eye a worked-out proposal for > keyword-based disposal methods could still meet the threshold of "small > change". Well, I'm happy to work it out. Then we'll have two alternatives to compare. Regards, Josh From xmirog at gmail.com Wed Mar 4 21:49:29 2009 From: xmirog at gmail.com (=?ISO-8859-1?Q?Xavi_Mir=F3?=) Date: Thu, 05 Mar 2009 06:49:29 +0100 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AF14C9.3050309@joda.org> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> <49AF14C9.3050309@joda.org> Message-ID: <49AF67E9.6020004@gmail.com> I like the simplicity of Josh' solution, the rule of throwing the most important exception (the first) and silent the others, using an interface whose method close simply throws Exception...For the Java source code I've been writing for the last 10 years it would fit 100%, I can't remember any "corner case" where it wouldn't fit well, but of course if we can apply this solution to more use cases without losing much simplicity, that would be perfect. For me, using a modifier like finally would also be acceptable. I would love to have this ARM proposal in Java 7! Xavi Stephen Colebourne wrote: > > interface Disposable { > > void close() throws Exception; > > } > > interface Destroyable { > > void dispose() throws Exception; > > } > > interface Kloseable { > > void destroy() throws Exception; > > } > > Er, no. If its to be an interface it needs to be just one. > > A single interface - Disposable defining close() covers most use cases, > and API writers would adapt in the future. > > >> public finally void release() { ... } >> > > I think this works well, and opens up more options. Are there any > specific grammer objections? > > It would be possible to add a marker interface Finally which enforces > the presence of the finally modifier, but that seems to have little > obvious benefit, and be a bit magical. > > Stephen > > > From Joe.Darcy at Sun.COM Wed Mar 4 23:05:04 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 23:05:04 -0800 Subject: Project Coin so far, suggestions for refining current proposals and improving new ones Message-ID: <49AF79A0.7040509@sun.com> Greetings. After a few short days, Project Coin has already received over 10 proposal submissions! Thanks for the insightful feedback and analysis that has been occurring on the list. A few general comments on the proposals that have been sent in so far to help refine those proposals and improve future proposals before they are sent in. The proposals submitted to Project Coin should already be well thought-through. The goal is to have in short order specifications approaching JLS quality, preferably with a prototype to help validate the design. The feedback on the list should be much closer to finding and illuminating any remaining dark corners of a proposal rather than fleshing out its basic structure. If a proposal does not cite chapter and verse of the JLS for parts of its specification, that is a good indication the proposal is too vague. All affected sections of the JLS should be listed, including binary compatibility and the flow analysis in definite assignment. It is fine if someone posts to the list to solicit help writing a proposal for a given change. Proposal writers should be aware of the size and scope parameters established for the project; for background see "Criteria for desirable small language changes" http://blogs.sun.com/darcy/entry/criteria_for_desirable_small_language "Guidance on measuring the size of a language change" http://blogs.sun.com/darcy/entry/guidance_measure_language_change_size Also, proposal writers should search Sun's bug database for bugs related to the change. The URL for the database is http://bugs.sun.com; Java specification issues are in category Java SE and subcategory specification. Of course the database is also searchable with your favorite search engine restricted to that site. Besides the evaluation field from the bug database, the external comment can often also have valuable insight into and discussion of alternatives to solving the problem or reasons why the problem shouldn't be solved. As has already been happening on the list, authors and advocates of a proposal are responsible for responding to feedback and incorporating changes into any subsequent iterations of the proposal. For now, I think it is adequate to just send the revised proposals to the list. Only if there turns out to be frequent change would a more formal tracking system be warranted. Keeping such discussions on the list is important both to allow easy, centralized tracking of the proposal drafts and also for future language archaeologists who are curious about why a particular decision was made. After a few iterations of feedback and refinements, the specification and compilation strategy should be sufficiently detailed to provide high-confidence that the proposal is practical and can be reduced to practice. For example, I think the initial proposal, [1], for the admittedly simple strings in switch change provides adequate detail on these fronts. -Joe [1] http://mail.openjdk.java.net/pipermail/coin-dev/2009-February/000001.html PS I've reconfigured the list to accept HTML messages. To get an HTML message through, just send HTML, not HTML and text. From jjb at google.com Wed Mar 4 23:15:30 2009 From: jjb at google.com (Joshua Bloch) Date: Wed, 4 Mar 2009 23:15:30 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <49AF67E9.6020004@gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> <49AF14C9.3050309@joda.org> <49AF67E9.6020004@gmail.com> Message-ID: <17b2302a0903042315l26e012f3s68b7bd48b81bcaa7@mail.gmail.com> Xavi, Thanks very much for the feedback! Josh On Wed, Mar 4, 2009 at 9:49 PM, Xavi Mir? wrote: > I like the simplicity of Josh' solution, the rule of throwing the most > important exception (the first) and silent the others, using an > interface whose method close simply throws Exception...For the Java > source code I've been writing for the last 10 years it would fit 100%, I > can't remember any "corner case" where it wouldn't fit well, but of > course if we can apply this solution to more use cases without losing > much simplicity, that would be perfect. > > For me, using a modifier like finally would also be acceptable. > > I would love to have this ARM proposal in Java 7! > > Xavi > > Stephen Colebourne wrote: > > > interface Disposable { > > > void close() throws Exception; > > > } > > > interface Destroyable { > > > void dispose() throws Exception; > > > } > > > interface Kloseable { > > > void destroy() throws Exception; > > > } > > > > Er, no. If its to be an interface it needs to be just one. > > > > A single interface - Disposable defining close() covers most use cases, > > and API writers would adapt in the future. > > > > > >> public finally void release() { ... } > >> > > > > I think this works well, and opens up more options. Are there any > > specific grammer objections? > > > > It would be possible to add a marker interface Finally which enforces > > the presence of the finally modifier, but that seems to have little > > obvious benefit, and be a bit magical. > > > > Stephen > > > > > > > > > From Joe.Darcy at Sun.COM Wed Mar 4 23:28:02 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Wed, 04 Mar 2009 23:28:02 -0800 Subject: PROPOSAL: Static Methods in Interfaces In-Reply-To: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> References: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> Message-ID: <49AF7F02.20901@sun.com> A quick note... Reinier Zwitserloot wrote: > Apparently the previous version's attachment didn't come through > properly, so here's an inline HTML version. > > Static Methods in Interfaces > > VERSION > > > [snip] > REFERENCES > > EXISTING BUGS: > > None. > See http://bugs.sun.com/view_bug.do?bug_id=4093687 -Joe From rssh at gradsoft.com.ua Wed Mar 4 23:52:17 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Thu, 5 Mar 2009 09:52:17 +0200 (EET) Subject: String literals in Java 7: version 1.2 Message-ID: <78bb9da52f93ca2910ebca9fe346fd8a.squirrel@wmail.gradsoft.ua> Summary of changes: - methods for setting LF type in strings instead suffixes. - add line-termination escape sequence. (as in C and groovy) Proposal itself: 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') stings - 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()); } String platformDepended="""q """.nativeLf(); is 'q\n' if compiled on Unix and 'q\n\r' if compiled on Windows. String platformIndepended="""q """; is always "q\n". String platformIndepended="""q """U.unixLf(); is the same. String platformIndepended=""" """.windowsLf(); is always '\r\n'. Unescaped String: String myParrern=''..*\.*''; instead String myParrern="\..*\\.*"; String fname=''C:\Program Files\My Program\Configuration''; instead String myParrern="C:\\Program Files\\My Program\\Configuration"; ADVANCED EXAMPLE: String empty=""" """; is empty. String foo = """ bar baz bla qux"; is equal to: String foo = "bar\n baz\n bla\nqux"; String foo = """ foo bar"""; is a compile-time error. String manyQuotes="""\"""\"\"\""""; is """"" String s = """I'm long string in groovy stile wi\ th \\ at end of line"""; is: I'm long string in groovy stile with \ at end of line String s = ''I'm long string in groovy stile wi\ th \\ at end of line''; is: I'm long string in groovy stile wi\ th \\ at end of line 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 """

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

MultilineStringCharacter:
        InputCharacter but not \
        EscapeSequence
        LineTermination
        EolEscapeSequence

EolEscapeSequence: \ LineTermination.

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

 RowInputCharacters:
                      ' (InputCharacter but not ')
                     |
                      (InputCharacter but not ') '
                     |
                      LineTermination
Methods for replacing line termination sequences in string to native format of host platform, and to well-known unix/windows formats must be added to standard library. COMPILATION: Handling of multiline strings: Text within """ brackets processed in next way: 1. splitted to sequence of lines by line termination symbols. 2. sequence \LineTermination at the end of line is erased and such line cause line be concatenated with next line in one. (if nextline exists, otherwise - throw compile-trime error) 3. escape sequences in each line are processed exactly as in ordinary Java strings. 4. elimination of leading whitespaces are processed in next way: - at first determinate 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 5. set of lines after erasing of leading whitespace sequence is concatenated, with LF (i. e. '\n') line-termination sequences between two neighbour lines, regardless of host system Handling of row strings: Text within '' 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 '\n' line-termination sequences between two neighbour lines, 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: add new strings literals to test-cases for all combinations of finished and unfinished escape sequences and quotes. LIBRARY SUPPORT: Add to String next methods: s.platformLf() - returns string which replace all line-termination sequences in s by value of system property 'line.separator' s.unixLf() - returns string which replace all line-termination sequences in s by '\n' s.windowsLf() - returns string which replace all line-termination sequences in s by '\r\n' REFLECTIVE APIS: None OTHER CHANGES: None MIGRATION: None COMPABILITY None REFERENCES Sun bug database http://bugs.sun.com/view_bug.do?bug_id=4165111 http://bugs.sun.com/view_bug.do?bug_id=4472509 Multiline strings proposal in project Kijaro by by Jacek Furmankiewicz http://docs.google.com/View?docid=d36kv8n_32g9zj7pdd From schulz at e-Spirit.de Thu Mar 5 00:16:09 2009 From: schulz at e-Spirit.de (Schulz, Stefan) Date: Thu, 5 Mar 2009 09:16:09 +0100 Subject: PROPOSAL: Static Methods in Interfaces In-Reply-To: <49AEF383.2000607@joda.org> References: <3B8E7669-6E97-4591-A672-A26BB3F925D3@zwitserloot.com> <49AEF383.2000607@joda.org> Message-ID: <7D2077BFF677D2429DDDEE095D9A48AC102BE5A8@osiris2.e-spirit.de> Hi, > I'd like to > see Java support 'static implements': > > public class Foo implements Bar, static Baz { > ... > } > > where any methods defined by Baz have to be implemented by > Foo as static > methods. Someone might remember me writing about this topic under the name "Meta-interfaces/Contracts" in early 2008. I don't think the suggested static methods do collide with a feature to have 'static implements', as these don't need to employ static (abstract) methods, but rather set the scope of the whole interface to define contracts a class has to fulfill (in form of implementing static methods corresponding to the interface). While I shortly thought about posting a proposal on Contracts, I think it is far out of scope for Coin. Regarding static methods in interfaces, I feel a bit undecided, though. While it seems desireable to have common utility methods as close to the related interface as possible, interfaces might become polluted by those methods (as a nested class may do, too) and custom utilities still cannot be linked to the targeted interface. Maybe some possibility to establish a kind of link between utility classes and interfaces would be the better choice. In general, I'd rather prefer a solution like extension methods or similar solutions, accepting not to have it in Coin if considered to big a change. Cheers, Stefan From david.goodenough at linkchoose.co.uk Thu Mar 5 02:31:54 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Thu, 5 Mar 2009 10:31:54 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903041535.53432.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903041535.53432.david.goodenough@linkchoose.co.uk> Message-ID: <200903051031.55522.david.goodenough@linkchoose.co.uk> Thinking further about this, there is a problem with using Field objects. Field objects predate Generics, and so the getter/setter that it provides is not one that the compiler/IDE can check. This is real problem and undermines one of the important drivers for this proposal. Now one could rewrite Field to require Generics, but that would break so much code that is is not something I would want to contemplate. In addition applying that to Methods would be well neigh impossible. There is a further problem, which is that as I read it the FCM proposal is only for a single Field object, where my Property object actually holds a Field array, so that it can handle Foo#bar#ali. All in all, I think that introducing a new class (my Property class) solves both the problems, not breaking any existing code and building something that is type safe and checkable and that FCM could subsequently build upon. David On Wednesday 04 March 2009, David Goodenough wrote: > On Wednesday 04 March 2009, Roel Spilker wrote: > > In your proposal, foo#bar would be translated by the compiler into: new > > Property(foo,"bar"); > > > > But I think you should split your proposal into two parts. The first part > > is using the Foo#bar syntax to be a field literal for the field "bar" in > > the type "Foo". This is similar to the FCM proposal > > (http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc). So it would be a > > java.lang.reflect.Field literal. > > > > The second part would be a proposal to build properties using field > > literals. > > > > I give the field literal proposal a chance to be included. > > > > Roel > > I would not be unhappy with that, if were it possible. But I think that > due to the way that Field objects are represented in the class file (in an > odd binary format) and then constructed at run time, that this would not be > possible. It is important (for things like accessing Annotations) that we > get the REAL Field object, and not a partial copy or lookalike. > > If someone can come up with a way of doing that I would be delighted. > > David > > > -----Oorspronkelijk bericht----- > > Van: david.goodenough at linkchoose.co.uk > > [mailto:coin-dev-bounces at openjdk.java.net] Namens David Goodenough > > Verzonden: woensdag 4 maart 2009 10:50 > > Aan: coin-dev at openjdk.java.net > > Onderwerp: Re: PROPOSAL: Lightweight Properties > > > > I am not sure that we would loose anything. The important thing is to > > have an IDE/compiler checkable way of generating Property objects, and > > having two ways of generating them is not really a problem. My Property > > object would happily detect either an explicitly generated getter/setter > > or one generated for you by a property keyword. The property keyword > > would resolve other things (like the automatic generation of > > PropertyChangeSupport, and the controlling of visibility) but it is still > > building on the same basic concept. > > > > If you don't want to use # then the work needed for the compiler gets > > more complicated (I think). One could use a sort of compiler function, > > so one would say property(foo.bar) and it would modify the function of . > > inside the function. > > > > I really want to find a way to get something into Java 7, otherwise we > > are looking to Java 8 (which is at least 3 years away if current > > timescales persist), by which time I suspect that everyone will have > > gotten bored and gone to find pastures new. > > > > David > > > > On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > > > But it seems that we _would_ lose a thing or two with this proposal. > > > For example, if a complete properties proposal supports full backwards > > > compatibility and generates getters and setters, then we have a bunch > > > of code around that uses the foo#bar notation, which is by then > > > already outdated, and would in fact get in the way of using foo#bar > > > notation as a shorthand for calling the appropriate getter/setter. I > > > don't know if that is a desired syntax sugar, but the point is: Your > > > proposal would effectively make it impossible to add that later, as it > > > would already be shorthand for creating a Property object. > > > > > > The # and the backtick are the only easily typed symbols that have no > > > meaning whatsoever in java right now. Using one up for an simplified > > > properties proposal is another serious disdvantage. I don't think your > > > proposal makes property support light enough to warrant its inclusion > > > in project coin. That's not to say I have something against > > > properties; on the contrary, I love the idea and I'm very impressed > > > with the way properties work in JavaFX. All the more reason to get it > > > right instead of using a bandage. > > > > > > --Reinier Zwitserloot > > > > > > On Mar 3, 2009, at 23:00, David Goodenough wrote: > > > > 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 reinier at zwitserloot.com Thu Mar 5 07:18:00 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Thu, 5 Mar 2009 16:18:00 +0100 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <2B16F0B2-3463-451D-BA28-01A4D5EB4E7C@zwitserloot.com> <15e8b9d20903031847g142dc043je47dafed271f3853@mail.gmail.com> <17b2302a0903031947g75dc9a6n908b959bfb57c0d2@mail.gmail.com> <17b2302a0903041109rd051b7eh60a72830e86fa970@mail.gmail.com> <685C7A2B-36FE-4607-BA27-8EC4646DDF70@googlemail.com> <63b4e4050903041440k61fd90bdi1e7b9e70698e9de3@mail.gmail.com> <17b2302a0903041517t3b05d48aw88ae62fd24fd4c82@mail.gmail.com> Message-ID: I like the 'finally' keyword idea, but I don't think its neccessarily a good idea to call such classes 'Resources'. Is a lock a resource? (Talking about the general concept here, not any particular implementation). Not sure if that's the right term. It is feasibly something that would have a finally method? Absolutely. Micro-benchmarking is bad, but theoretically, if you wanted to, you could use an ARM-style block to do the job. That's definitely not a resource, and not neccessarily a bright idea, but I hope it gets the point across: The notion of being able to create an object, where that object gets notified if the thread exits the block, no matter how it does so, is sufficiently useful that it will be used by things that aren't neccessarily a 'Resource'. Then again, javadoc should definitely explain that you can use an instance of a class in a guarded block like that, and it'll need some sort of convenient term. "Guarded" is all I can come up with, which doesn't really sound right either. There's an established tradition in the programming world of terms taking on their own meaning. (After all, isn't "static" suggestive of 'constant', even though it has nothing to do with that? The term has been internalized as jargon). --Reinier Zwitserloot On Mar 5, 2009, at 00:17, Joshua Bloch wrote: > Tim, > Hi! > > On Wed, Mar 4, 2009 at 2:40 PM, Tim Peierls wrote: > >> I've never understood the fervor with which Java is defended from >> annotations that can change program semantics; the defenders' >> arguments >> always sound suspiciously circular. But never mind that ... I >> confess that >> even though I would have been happy with >> >> @Finally public void release() { ... } >> >> I'd much prefer >> >> public finally void release() { ... } >> > > I think it's worth adding this to the proposal as a design > alternative. The > finally modifier could appear on one and only one method. It would > have to > be a public, parameterless instance method. This would require a > (small) > class file format change, and a change to the JavaDoc tool, which > would > document that the class was a "resource," and which method was its > disposal > method. It would make the automatic resource management statement a > bit > more broadly applicable at the expense of a bit of added complexity. > > Josh > >> > From david.goodenough at linkchoose.co.uk Thu Mar 5 07:27:51 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Thu, 5 Mar 2009 15:27:51 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <0DD690C3-C084-4E80-B74A-353B2657D277@zwitserloot.com> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051031.55522.david.goodenough@linkchoose.co.uk> <0DD690C3-C084-4E80-B74A-353B2657D277@zwitserloot.com> Message-ID: <200903051527.53497.david.goodenough@linkchoose.co.uk> Rienier, Yes I know that Fields have Generics information available, but they are not used in the declaration of a Field object, and so the getter and setter to the value of the field are NOT typed, and thus can not be checked by the compiler/IDE. I do not have the knowledge to add this to the compiler, and the only documentation I have found for adding things to the compiler (as I have already mentioned) did not help - it only talked about adding operators to the compiler. The compiler is not exactly well documented or if it is, Google has been unable to furnish the right documents. The reason that it is needed is very simple. One of the big strengths of Java is that compilers and IDEs can do a really good job of detecting errors, and in the case of IDEs making suggestions as to what can come next. Using String field names in places like Bean Binding frameworks and API approaches to SQL and friends (like the JPA Criteria API) drives a coach and horses through that strength. For that reason, and the fact that this is a VERY simple suggestion, this proposal should be given serious consideration. Now if there people out there with the knowledge to help me get started in understanding what needs to be changed in Javac (I tried Remi Forax as he had already worked in this area, but he was too busy to help when I asked) I am more than happy to try to produce a working javac. But simply jumping into the source from scratch is unlikely to produce a good solution. So perhaps rather than spending our time throwing out reasons why this can not be done, lets try to work together to find a way in which is can be done. David On Thursday 05 March 2009, you wrote: > I think you'll need to spend some more time getting familiar with the > JLS. > > For example, Field objects *DO* have generics information. That's what > Field.getGenericType() is for. > > I -really- doubt you'll get anywhere with your proposal unless you do > both of the following: > > - impress everybody with an exceedingly complete proposal along with > a prototype implementation of javac. Which is going to take a lot more > working knowledge of the JLS and how javac parses source files than > you currently have. > > - either a grassroots campaign of many java programmers that > vindicates your insinuation that properties are so important, they > need to be added to java7, even with this bandaid solution, or > alternatively, convince a number of property evangelising people in > the java community to openly speak in favour of this proposal. > > I imagine that's going to cost you a week or 5 at the very least of > your time, including getting more familiar with the JLS. March is > going to be over by then. > > --Reinier Zwitserloot > > On Mar 5, 2009, at 11:31, David Goodenough wrote: > > Thinking further about this, there is a problem with using Field > > objects. > > > > Field objects predate Generics, and so the getter/setter that it > > provides > > is not one that the compiler/IDE can check. This is real problem and > > undermines one of the important drivers for this proposal. > > > > Now one could rewrite Field to require Generics, but that would break > > so much code that is is not something I would want to contemplate. > > In addition applying that to Methods would be well neigh impossible. > > > > There is a further problem, which is that as I read it the FCM > > proposal > > is only for a single Field object, where my Property object actually > > holds a Field array, so that it can handle Foo#bar#ali. > > > > All in all, I think that introducing a new class (my Property class) > > solves > > both the problems, not breaking any existing code and building > > something > > that is type safe and checkable and that FCM could subsequently build > > upon. > > > > David > > > > On Wednesday 04 March 2009, David Goodenough wrote: > >> On Wednesday 04 March 2009, Roel Spilker wrote: > >>> In your proposal, foo#bar would be translated by the compiler > >>> into: new > >>> Property(foo,"bar"); > >>> > >>> But I think you should split your proposal into two parts. The > >>> first part > >>> is using the Foo#bar syntax to be a field literal for the field > >>> "bar" in > >>> the type "Foo". This is similar to the FCM proposal > >>> (http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc). So it would be a > >>> java.lang.reflect.Field literal. > >>> > >>> The second part would be a proposal to build properties using field > >>> literals. > >>> > >>> I give the field literal proposal a chance to be included. > >>> > >>> Roel > >> > >> I would not be unhappy with that, if were it possible. But I think > >> that > >> due to the way that Field objects are represented in the class file > >> (in an > >> odd binary format) and then constructed at run time, that this > >> would not be > >> possible. It is important (for things like accessing Annotations) > >> that we > >> get the REAL Field object, and not a partial copy or lookalike. > >> > >> If someone can come up with a way of doing that I would be delighted. > >> > >> David > >> > >>> -----Oorspronkelijk bericht----- > >>> Van: david.goodenough at linkchoose.co.uk > >>> [mailto:coin-dev-bounces at openjdk.java.net] Namens David Goodenough > >>> Verzonden: woensdag 4 maart 2009 10:50 > >>> Aan: coin-dev at openjdk.java.net > >>> Onderwerp: Re: PROPOSAL: Lightweight Properties > >>> > >>> I am not sure that we would loose anything. The important thing > >>> is to > >>> have an IDE/compiler checkable way of generating Property objects, > >>> and > >>> having two ways of generating them is not really a problem. My > >>> Property > >>> object would happily detect either an explicitly generated getter/ > >>> setter > >>> or one generated for you by a property keyword. The property > >>> keyword > >>> would resolve other things (like the automatic generation of > >>> PropertyChangeSupport, and the controlling of visibility) but it > >>> is still > >>> building on the same basic concept. > >>> > >>> If you don't want to use # then the work needed for the compiler > >>> gets > >>> more complicated (I think). One could use a sort of compiler > >>> function, > >>> so one would say property(foo.bar) and it would modify the > >>> function of . > >>> inside the function. > >>> > >>> I really want to find a way to get something into Java 7, > >>> otherwise we > >>> are looking to Java 8 (which is at least 3 years away if current > >>> timescales persist), by which time I suspect that everyone will have > >>> gotten bored and gone to find pastures new. > >>> > >>> David > >>> > >>> On Tuesday 03 March 2009, Reinier Zwitserloot wrote: > >>>> But it seems that we _would_ lose a thing or two with this > >>>> proposal. > >>>> For example, if a complete properties proposal supports full > >>>> backwards > >>>> compatibility and generates getters and setters, then we have a > >>>> bunch > >>>> of code around that uses the foo#bar notation, which is by then > >>>> already outdated, and would in fact get in the way of using foo#bar > >>>> notation as a shorthand for calling the appropriate getter/ > >>>> setter. I > >>>> don't know if that is a desired syntax sugar, but the point is: > >>>> Your > >>>> proposal would effectively make it impossible to add that later, > >>>> as it > >>>> would already be shorthand for creating a Property object. > >>>> > >>>> The # and the backtick are the only easily typed symbols that > >>>> have no > >>>> meaning whatsoever in java right now. Using one up for an > >>>> simplified > >>>> properties proposal is another serious disdvantage. I don't think > >>>> your > >>>> proposal makes property support light enough to warrant its > >>>> inclusion > >>>> in project coin. That's not to say I have something against > >>>> properties; on the contrary, I love the idea and I'm very impressed > >>>> with the way properties work in JavaFX. All the more reason to > >>>> get it > >>>> right instead of using a bandage. > >>>> > >>>> --Reinier Zwitserloot > >>>> > >>>> On Mar 3, 2009, at 23:00, David Goodenough wrote: > >>>>> 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 Thu Mar 5 08:41:02 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Thu, 5 Mar 2009 17:41:02 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903051527.53497.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051031.55522.david.goodenough@linkchoose.co.uk> <0DD690C3-C084-4E80-B74A-353B2657D277@zwitserloot.com> <200903051527.53497.david.goodenough@linkchoose.co.uk> Message-ID: <28bca0ff0903050841n7751a3d0yfc268b408b071475@mail.gmail.com> 2009/3/5 David Goodenough > Rienier, > > Yes I know that Fields have Generics information available, but they are > not used in the declaration of a Field object, and so the getter and > setter to the value of the field are NOT typed, and thus can not be > checked by the compiler/IDE. > > I do not have the knowledge to add this to the compiler, and the only > documentation I have found for adding things to the compiler (as I > have already mentioned) did not help - it only talked about adding > operators to the compiler. The compiler is not exactly well documented > or if it is, Google has been unable to furnish the right documents. > > The reason that it is needed is very simple. One of the big strengths > of Java is that compilers and IDEs can do a really good job of detecting > errors, and in the case of IDEs making suggestions as to what can come > next. Using String field names in places like Bean Binding frameworks > and API approaches to SQL and friends (like the JPA Criteria API) drives > a coach and horses through that strength. For that reason, and the fact > that this is a VERY simple suggestion, this proposal should be given > serious consideration. > > Now if there people out there with the knowledge to help me get started > in understanding what needs to be changed in Javac (I tried Remi Forax > as he had already worked in this area, but he was too busy to help when > I asked) I am more than happy to try to produce a working javac. But > simply jumping into the source from scratch is unlikely to produce a good > solution. > > So perhaps rather than spending our time throwing out reasons why this > can not be done, lets try to work together to find a way in which is can > be done. > > David > > On Thursday 05 March 2009, you wrote: > > I think you'll need to spend some more time getting familiar with the > > JLS. > > > > For example, Field objects *DO* have generics information. That's what > > Field.getGenericType() is for. > > > > I -really- doubt you'll get anywhere with your proposal unless you do > > both of the following: > > > > - impress everybody with an exceedingly complete proposal along with > > a prototype implementation of javac. Which is going to take a lot more > > working knowledge of the JLS and how javac parses source files than > > you currently have. > > > > - either a grassroots campaign of many java programmers that > > vindicates your insinuation that properties are so important, they > > need to be added to java7, even with this bandaid solution, or > > alternatively, convince a number of property evangelising people in > > the java community to openly speak in favour of this proposal. > > > > I imagine that's going to cost you a week or 5 at the very least of > > your time, including getting more familiar with the JLS. March is > > going to be over by then. > > > > --Reinier Zwitserloot > > > I do not see the problem you have. If you have 'static' name of field (only then compiler can check it) then you can simply use field. If u do not have that information (it's dynamic) then also compiler is unable to determine it's type before execution. That why I do not see why we need any other solution than linking 'Fields' with fields to make it refactor friendly and easy to use. Am I wrong? -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Thu Mar 5 09:09:44 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Thu, 5 Mar 2009 17:09:44 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <28bca0ff0903050841n7751a3d0yfc268b408b071475@mail.gmail.com> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051527.53497.david.goodenough@linkchoose.co.uk> <28bca0ff0903050841n7751a3d0yfc268b408b071475@mail.gmail.com> Message-ID: <200903051709.46250.david.goodenough@linkchoose.co.uk> On Thursday 05 March 2009, Marek Kozie? wrote: > 2009/3/5 David Goodenough > > > Rienier, > > > > Yes I know that Fields have Generics information available, but they are > > not used in the declaration of a Field object, and so the getter and > > setter to the value of the field are NOT typed, and thus can not be > > checked by the compiler/IDE. > > > > I do not have the knowledge to add this to the compiler, and the only > > documentation I have found for adding things to the compiler (as I > > have already mentioned) did not help - it only talked about adding > > operators to the compiler. The compiler is not exactly well documented > > or if it is, Google has been unable to furnish the right documents. > > > > The reason that it is needed is very simple. One of the big strengths > > of Java is that compilers and IDEs can do a really good job of detecting > > errors, and in the case of IDEs making suggestions as to what can come > > next. Using String field names in places like Bean Binding frameworks > > and API approaches to SQL and friends (like the JPA Criteria API) drives > > a coach and horses through that strength. For that reason, and the fact > > that this is a VERY simple suggestion, this proposal should be given > > serious consideration. > > > > Now if there people out there with the knowledge to help me get started > > in understanding what needs to be changed in Javac (I tried Remi Forax > > as he had already worked in this area, but he was too busy to help when > > I asked) I am more than happy to try to produce a working javac. But > > simply jumping into the source from scratch is unlikely to produce a good > > solution. > > > > So perhaps rather than spending our time throwing out reasons why this > > can not be done, lets try to work together to find a way in which is can > > be done. > > > > David > > > > On Thursday 05 March 2009, you wrote: > > > I think you'll need to spend some more time getting familiar with the > > > JLS. > > > > > > For example, Field objects *DO* have generics information. That's what > > > Field.getGenericType() is for. > > > > > > I -really- doubt you'll get anywhere with your proposal unless you do > > > both of the following: > > > > > > - impress everybody with an exceedingly complete proposal along with > > > a prototype implementation of javac. Which is going to take a lot more > > > working knowledge of the JLS and how javac parses source files than > > > you currently have. > > > > > > - either a grassroots campaign of many java programmers that > > > vindicates your insinuation that properties are so important, they > > > need to be added to java7, even with this bandaid solution, or > > > alternatively, convince a number of property evangelising people in > > > the java community to openly speak in favour of this proposal. > > > > > > I imagine that's going to cost you a week or 5 at the very least of > > > your time, including getting more familiar with the JLS. March is > > > going to be over by then. > > > > > > --Reinier Zwitserloot > > I do not see the problem you have. > > If you have 'static' name of field (only then compiler can check it) then > you can simply use field. Well no, because if you need to use an explicit getter or setter to do some extra processing or in the setter you want to fire a PropertyChangeEvent then the Field on its own is not enough. The Field setter could be extended, but as it does not know the parent object (the think of which this is a Field) it can not look for a PropertyChangeSupport object. The Field set method does not try to fire PropertyChangeEvents, and does not provide to use an explicitly coded setter. That could be got around by passing the Field object into a Property constructor, rather than the field names, but again we do not have access to the parent object which makes searching for getters and setters and PropertyChangeSupport objects rather difficult. > > If u do not have that information (it's dynamic) then also compiler is > unable to determine it's type before execution. true > > That why I do not see why we need any other solution than linking 'Fields' > with fields to make it refactor friendly and easy to use. I do not see (maybe I did not understand FCM) how I could handle foo#bar#ali. In this case you need a Field array, not just a field. Additionally the FCM case only seems to handle the Foo#bar case, not the foo#bar case. That is not the end of the world - it would work in the examples I need, but it is less than my proposal covers. > > Am I wrong? Either I have missunderstood the FCM (which is quite possible) or it does not match what my proposal offers. David From develop4lasu at gmail.com Thu Mar 5 09:25:07 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Thu, 5 Mar 2009 18:25:07 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903051709.46250.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051527.53497.david.goodenough@linkchoose.co.uk> <28bca0ff0903050841n7751a3d0yfc268b408b071475@mail.gmail.com> <200903051709.46250.david.goodenough@linkchoose.co.uk> Message-ID: <28bca0ff0903050925u21245b22lb750469e64174c05@mail.gmail.com> 2009/3/5 David Goodenough > On Thursday 05 March 2009, Marek Kozie? wrote: > > 2009/3/5 David Goodenough > > > > > Rienier, > > > > > > Yes I know that Fields have Generics information available, but they > are > > > not used in the declaration of a Field object, and so the getter and > > > setter to the value of the field are NOT typed, and thus can not be > > > checked by the compiler/IDE. > > > > > > I do not have the knowledge to add this to the compiler, and the only > > > documentation I have found for adding things to the compiler (as I > > > have already mentioned) did not help - it only talked about adding > > > operators to the compiler. The compiler is not exactly well documented > > > or if it is, Google has been unable to furnish the right documents. > > > > > > The reason that it is needed is very simple. One of the big strengths > > > of Java is that compilers and IDEs can do a really good job of > detecting > > > errors, and in the case of IDEs making suggestions as to what can come > > > next. Using String field names in places like Bean Binding frameworks > > > and API approaches to SQL and friends (like the JPA Criteria API) > drives > > > a coach and horses through that strength. For that reason, and the > fact > > > that this is a VERY simple suggestion, this proposal should be given > > > serious consideration. > > > > > > Now if there people out there with the knowledge to help me get started > > > in understanding what needs to be changed in Javac (I tried Remi Forax > > > as he had already worked in this area, but he was too busy to help when > > > I asked) I am more than happy to try to produce a working javac. But > > > simply jumping into the source from scratch is unlikely to produce a > good > > > solution. > > > > > > So perhaps rather than spending our time throwing out reasons why this > > > can not be done, lets try to work together to find a way in which is > can > > > be done. > > > > > > David > > > > > > On Thursday 05 March 2009, you wrote: > > > > I think you'll need to spend some more time getting familiar with the > > > > JLS. > > > > > > > > For example, Field objects *DO* have generics information. That's > what > > > > Field.getGenericType() is for. > > > > > > > > I -really- doubt you'll get anywhere with your proposal unless you do > > > > both of the following: > > > > > > > > - impress everybody with an exceedingly complete proposal along > with > > > > a prototype implementation of javac. Which is going to take a lot > more > > > > working knowledge of the JLS and how javac parses source files than > > > > you currently have. > > > > > > > > - either a grassroots campaign of many java programmers that > > > > vindicates your insinuation that properties are so important, they > > > > need to be added to java7, even with this bandaid solution, or > > > > alternatively, convince a number of property evangelising people in > > > > the java community to openly speak in favour of this proposal. > > > > > > > > I imagine that's going to cost you a week or 5 at the very least of > > > > your time, including getting more familiar with the JLS. March is > > > > going to be over by then. > > > > > > > > --Reinier Zwitserloot > > > > I do not see the problem you have. > > > > If you have 'static' name of field (only then compiler can check it) then > > you can simply use field. > Well no, because if you need to use an explicit getter or setter to do some > extra processing or in the setter you want to fire a PropertyChangeEvent > then the Field on its own is not enough. > > The Field setter could be extended, but as it does not know the parent > object (the think of which this is a Field) it can not look for a > PropertyChangeSupport object. The Field set method does not try > to fire PropertyChangeEvents, and does not provide to use an > explicitly coded setter. That could be got around by passing the > Field object into a Property constructor, rather than the field names, > but again we do not have access to the parent object which makes > searching for getters and setters and PropertyChangeSupport objects > rather difficult. > > > > If u do not have that information (it's dynamic) then also compiler is > > unable to determine it's type before execution. > true > > > > That why I do not see why we need any other solution than linking > 'Fields' > > with fields to make it refactor friendly and easy to use. > I do not see (maybe I did not understand FCM) how I could handle > foo#bar#ali. In this case you need a Field array, not just a field. > Additionally the FCM case only seems to handle the Foo#bar case, > not the foo#bar case. That is not the end of the world - it would work > in the examples I need, but it is less than my proposal covers. > > > > Am I wrong? > Either I have missunderstood the FCM (which is quite possible) or it does > not > match what my proposal offers. > > David > > > So why not use Fields when it's needed. And mix it with: class YoursClass{ private final Container field = new Container(); } where Container: class final Container{ private Type element; public Type get(){ return element;} public void set(Type element){ /* validate */ /* evens before */ this.element=element; /* evens after */ } } Pesonaly I use Container mixed with validators. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Thu Mar 5 09:36:07 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Thu, 5 Mar 2009 17:36:07 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <28bca0ff0903050925u21245b22lb750469e64174c05@mail.gmail.com> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051709.46250.david.goodenough@linkchoose.co.uk> <28bca0ff0903050925u21245b22lb750469e64174c05@mail.gmail.com> Message-ID: <200903051736.09311.david.goodenough@linkchoose.co.uk> On Thursday 05 March 2009, Marek Kozie? wrote: > 2009/3/5 David Goodenough > > > On Thursday 05 March 2009, Marek Kozie? wrote: > > > 2009/3/5 David Goodenough > > > > > > > Rienier, > > > > > > > > Yes I know that Fields have Generics information available, but they > > > > are > > > > > > not used in the declaration of a Field object, and so the getter and > > > > setter to the value of the field are NOT typed, and thus can not be > > > > checked by the compiler/IDE. > > > > > > > > I do not have the knowledge to add this to the compiler, and the only > > > > documentation I have found for adding things to the compiler (as I > > > > have already mentioned) did not help - it only talked about adding > > > > operators to the compiler. The compiler is not exactly well > > > > documented or if it is, Google has been unable to furnish the right > > > > documents. > > > > > > > > The reason that it is needed is very simple. One of the big > > > > strengths of Java is that compilers and IDEs can do a really good job > > > > of > > > > detecting > > > > > > errors, and in the case of IDEs making suggestions as to what can > > > > come next. Using String field names in places like Bean Binding > > > > frameworks and API approaches to SQL and friends (like the JPA > > > > Criteria API) > > > > drives > > > > > > a coach and horses through that strength. For that reason, and the > > > > fact > > > > > > that this is a VERY simple suggestion, this proposal should be given > > > > serious consideration. > > > > > > > > Now if there people out there with the knowledge to help me get > > > > started in understanding what needs to be changed in Javac (I tried > > > > Remi Forax as he had already worked in this area, but he was too busy > > > > to help when I asked) I am more than happy to try to produce a > > > > working javac. But simply jumping into the source from scratch is > > > > unlikely to produce a > > > > good > > > > > > solution. > > > > > > > > So perhaps rather than spending our time throwing out reasons why > > > > this can not be done, lets try to work together to find a way in > > > > which is > > > > can > > > > > > be done. > > > > > > > > David > > > > > > > > On Thursday 05 March 2009, you wrote: > > > > > I think you'll need to spend some more time getting familiar with > > > > > the JLS. > > > > > > > > > > For example, Field objects *DO* have generics information. That's > > > > what > > > > > > > Field.getGenericType() is for. > > > > > > > > > > I -really- doubt you'll get anywhere with your proposal unless you > > > > > do both of the following: > > > > > > > > > > - impress everybody with an exceedingly complete proposal along > > > > with > > > > > > > a prototype implementation of javac. Which is going to take a lot > > > > more > > > > > > > working knowledge of the JLS and how javac parses source files than > > > > > you currently have. > > > > > > > > > > - either a grassroots campaign of many java programmers that > > > > > vindicates your insinuation that properties are so important, they > > > > > need to be added to java7, even with this bandaid solution, or > > > > > alternatively, convince a number of property evangelising people in > > > > > the java community to openly speak in favour of this proposal. > > > > > > > > > > I imagine that's going to cost you a week or 5 at the very least of > > > > > your time, including getting more familiar with the JLS. March is > > > > > going to be over by then. > > > > > > > > > > --Reinier Zwitserloot > > > > > > I do not see the problem you have. > > > > > > If you have 'static' name of field (only then compiler can check it) > > > then you can simply use field. > > > > Well no, because if you need to use an explicit getter or setter to do > > some extra processing or in the setter you want to fire a > > PropertyChangeEvent then the Field on its own is not enough. > > > > The Field setter could be extended, but as it does not know the parent > > object (the think of which this is a Field) it can not look for a > > PropertyChangeSupport object. The Field set method does not try > > to fire PropertyChangeEvents, and does not provide to use an > > explicitly coded setter. That could be got around by passing the > > Field object into a Property constructor, rather than the field names, > > but again we do not have access to the parent object which makes > > searching for getters and setters and PropertyChangeSupport objects > > rather difficult. > > > > > If u do not have that information (it's dynamic) then also compiler is > > > unable to determine it's type before execution. > > > > true > > > > > That why I do not see why we need any other solution than linking > > > > 'Fields' > > > > > with fields to make it refactor friendly and easy to use. > > > > I do not see (maybe I did not understand FCM) how I could handle > > foo#bar#ali. In this case you need a Field array, not just a field. > > Additionally the FCM case only seems to handle the Foo#bar case, > > not the foo#bar case. That is not the end of the world - it would work > > in the examples I need, but it is less than my proposal covers. > > > > > Am I wrong? > > > > Either I have missunderstood the FCM (which is quite possible) or it does > > not > > match what my proposal offers. > > > > David > > > > > > So why not use Fields when it's needed. > > And mix it with: > > class YoursClass{ > > private final Container field = new Container(); > > } > > where Container: > > class final Container{ > > private Type element; > > public Type get(){ return element;} > > public void set(Type element){ /* validate */ /* evens before */ > this.element=element; /* evens after */ } > > } > > Pesonaly I use Container mixed with validators. Now you have lost me. I do not understand this or how it would help. David From develop4lasu at gmail.com Thu Mar 5 09:40:53 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Thu, 5 Mar 2009 18:40:53 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903051736.09311.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051709.46250.david.goodenough@linkchoose.co.uk> <28bca0ff0903050925u21245b22lb750469e64174c05@mail.gmail.com> <200903051736.09311.david.goodenough@linkchoose.co.uk> Message-ID: <28bca0ff0903050940v60551aefp37a36cdefb0f7673@mail.gmail.com> 2009/3/5 David Goodenough > > Now you have lost me. I do not understand this or how it would help. > > David > > You can use container to store element: Container field instead of: Field field And you can add listeners / validators to it, delegate it, ..... -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From david.goodenough at linkchoose.co.uk Thu Mar 5 09:56:49 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Thu, 5 Mar 2009 17:56:49 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <28bca0ff0903050940v60551aefp37a36cdefb0f7673@mail.gmail.com> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051736.09311.david.goodenough@linkchoose.co.uk> <28bca0ff0903050940v60551aefp37a36cdefb0f7673@mail.gmail.com> Message-ID: <200903051756.51085.david.goodenough@linkchoose.co.uk> On Thursday 05 March 2009, Marek Kozie? wrote: > 2009/3/5 David Goodenough > > > Now you have lost me. I do not understand this or how it would help. > > > > David > > You can use container to store element: > > Container field > > instead of: > > Field field > > And you can add listeners / validators to it, delegate it, ..... How does adding a Generics qualifier of Field help? Or is this an FCM thing? David From develop4lasu at gmail.com Thu Mar 5 11:40:54 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Thu, 5 Mar 2009 20:40:54 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903051756.51085.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051736.09311.david.goodenough@linkchoose.co.uk> <28bca0ff0903050940v60551aefp37a36cdefb0f7673@mail.gmail.com> <200903051756.51085.david.goodenough@linkchoose.co.uk> Message-ID: <28bca0ff0903051140s6204bacg204e7ccbc4ea7cfb@mail.gmail.com> 2009/3/5 David Goodenough > On Thursday 05 March 2009, Marek Kozie? wrote: > > 2009/3/5 David Goodenough > > > > > Now you have lost me. I do not understand this or how it would help. > > > > > > David > > > > You can use container to store element: > > > > Container field > > > > instead of: > > > > Field field > > > > And you can add listeners / validators to it, delegate it, ..... > > How does adding a Generics qualifier of Field help? Or is this an FCM > thing? > > David > > It's more like workaround. -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From belingueres at gmail.com Thu Mar 5 13:05:28 2009 From: belingueres at gmail.com (Gabriel Belingueres) Date: Thu, 5 Mar 2009 19:05:28 -0200 Subject: PROPOSAL: fold keyword In-Reply-To: References: Message-ID: Hi, This is a proposal for adding a simple "fold" operation on Collections. It is in a very draft state IMO, and perhaps it was already discussed in the process of adding closures to the language. Here I send it to you, nevertheless. Regards, Gabriel PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR(S): Gabriel Belingueres OVERVIEW Provide a "fold" sentence to Java for non trivial iterations over Collections. See http://en.wikipedia.org/wiki/Fold_(higher-order_function) FEATURE SUMMARY: Add the ability to support a form of "advanced for statement", to capture typical collection iteration patterns involving tests on some condition to break the iteration, or calculating a single value from the collection elements, assigning a default value when the collection is empty. The new "fold" keyword acts like a sugared, moderately complex enhanced for keyword that abstract this typical processing on collections. MAJOR ADVANTAGE: Makes the coding of not so trivial operations on collections more readable. MAJOR BENEFIT: Readability: Makes clearer the intention of the programmer when iterating over a collection to perform those typical but non trivial iterations. MAJOR DISADVANTAGE: Some increased implementation and testing complexity for the compiler. Add a new keyword for the language "fold". ALTERNATIVES: There are some free libraries like Apache's common-collection that helps in abstracting some aspects of complex collection iteration, however this library in particular is targeted for older java versions with no support for generics (others may do though). Libraries would need to pass the body of the for loop as an object, requiring to create an anonymous class, or making use of reflection to call the appropriate statements as if it where the body of the loop, making the implementation either less readable or less efficient, respectively. The full fledged alternative would be to add closures to Java (but closures seems to be not targeted for Java 7 AFAIK.) EXAMPLES SIMPLE EXAMPLE: ?List list = ArrayList(); ?l.add(...); ?// sum all numbers in the list ?Integer sum = ? ?fold(Integer n : list; ? ? // iterating collection element n ? ? ? ? Integer result = 0) { // Where to accumulate the result, and the initial value ? ? ?result += n; ? ?}; ?System.out.println(sum); ADVANCED EXAMPLES: ?// returns true if all salaries of the employee collection are lower than 1000 or the collection is empty. ?List emps = ....; ?Boolean allLower = ? ?fold(Employee emp : emps; ? ? ? ? Boolean result = Boolean.TRUE; ? ? ? ? !result) { ?// break condition: must be a boolean expression ? ? ?result = (emp.getSalary().compareTo(new BigDecimal(1000) < 0); ? ?} ?// returns a new collection with the salaries of the employees not on vacation ?List emps = ...; ?List salaries = ? ?fold(Employee e : emps; ? ? ? ? List newList = new ArrayList()) { ? ? ?if (!e.onVacation()) { ? ? ? ?newList.add(e.getSalary()); ? ? ?} ? ?} ?// returns the first N employees whose sum of salaries are lower than 1000000 ?List emps = ...; ?BigDecimal sum = BigDecimal.ZERO; // sum the salaries ?List selectedEmps = ? ?fold(Employee e : emps; ? ? ? ? List result = new ArrayList(); ? ? ? ? sum.add(e.getSalary()).compareTo(new BigDecimal(1000000)) < 0) { ? ? ? ? result.add(e); ? ? ? ? sum = sum.add(e.getSalary()); ? ?}; DETAILS SPECIFICATION: The following is somewhat informal, making emphasis in this draft document on the main idea instead of in formal grammar and JLS issues. SYNTAX: foldStatement: ? ?fold(VariableModifiers_opt Type Identifier: Expression; LocalVariableDeclaration; Expression_opt) Statement The first part is similar to what is required for the enhanced "for" keyword. The second part is a variable declaration that MUST be initialized with the value returned when the collection is empty. (It seems to me that it doesn't make any sense if the variable is declared "final".) Should be limited in scope to the fold body (to align the behavior with the for keyword). The third part is an optional boolean expression which acts as a break condition. The fold returns an object that is to be assignable from the same static type declared in the second part, which can be assigned to a variable or used as an expression. The behavior when the collection is null, or in the presence of exceptions should follow the same criteria than the enhanced for loop. COMPILATION: Here are desugarings to currently legal Java source for the two examples above: ? ?// simple example ? ?Integer sum; ? ?{ // new scope for synthetic variables ? ? ?Integer $result = 0; ? ? ?if (!list.isEmpty()) { // NPE if collection is null ? ? ? ?for(Integer n : list) { ? ? ? ? ?$result += n; ? ? ? ?} ? ? ?} ? ? ?sum = $result; ? ?} ? ?// first advanced example (with break condition) ? ?Boolean allLower; ? ?{ // new scope for synthetic variables ? ? ?Boolean $result = Boolean.TRUE; ? ? ?if (!emps.isEmpty()) { // NPE if collection is null ? ? ? ?for(Employee e : emps) { ? ? ? ? ?if (!$result) ? ? ? ? ? ?break; ? ? ? ? ?$result = (emp.getSalary().compareTo(new BigDecimal(1000)); ? ? ? ?} ? ? ?} ? ? ?allLower = $result; ? ?} TESTING: Generating various simple and complex uses of the new structure and verifying the proper execution results; combinations to test include fold statements with and without break conditions, tests with specific collection types such as Lists, Sets, Maps. Can expand on the enhanced for tests for further testing. LIBRARY SUPPORT: The same libraries that needs to be supported by the enhanced for loop. REFLECTIVE APIS: None of core reflection, javax.lang.model.*, the doclet API, and JDPA model statements; therefore, they are unaffected (AFAIK). The tree API in javac, does model statements, but maybe we can adapt the existing API for enhanced for statements. OTHER CHANGES: No. MIGRATION: Look for collection iterations with nested break conditions or element processing returning a single value. COMPATIBILITY BREAKING CHANGES: All existing programs remain valid. EXISTING PROGRAMS: The semantics of existing class files and legal source files are unchanged by this feature. REFERENCES EXISTING BUGS: None that I know about (doing a quick search on the bug database.) URL FOR PROTOTYPE (optional): No prototype at this time. From jjb at google.com Thu Mar 5 13:28:11 2009 From: jjb at google.com (Joshua Bloch) Date: Thu, 5 Mar 2009 13:28:11 -0800 Subject: PROPOSAL: fold keyword In-Reply-To: References: Message-ID: <17b2302a0903051328g5a98b084nd49d37339a0fa642@mail.gmail.com> Gabriel, This doesn't seem compelling. Here's your simple example: // sum all numbers in the list Integer sum = fold(Integer n : list; // iterating collection element n Integer result = 0) { // Where to accumulate the result, and the initial value result += n; }; } And here's how it looks today (with no change to the language or libraries): Integer sum = 0; for (Integer n : list) sum += n; Here's one of your complex examples: // returns a new collection with the salaries of the employees not on vacation List salaries = fold(Employee e : emps; List newList = new ArrayList()) { if (!e.onVacation()) { newList.add(e.getSalary()); } } And here's how it looks today: List salaries = new ArrayList(); for (Employee e : emps) if (!e.onVacation()) salaries.add(e.getSalary()); To my eyes, the current version is clearer as well as shorter. Josh From suranap at gmail.com Thu Mar 5 14:16:02 2009 From: suranap at gmail.com (Pinku Surana) Date: Thu, 5 Mar 2009 17:16:02 -0500 Subject: PROPOSAL: Multiple switch expressions and case ranges Message-ID: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> Has the switch statement in C languages evolved much since the '80s? I'm envious of the case/match expression in functional languages and looking for simple ways to make 'switch' more powerful. AUTHOR(S): Pinku Surana OVERVIEW FEATURE SUMMARY: Extend the switch statement to support multiple switch expressions and case ranges. MAJOR ADVANTAGE: It is syntactic sugar that makes it easier to write/read complex logic. This is one small aspect of the vastly more powerful match or case expression in functional languages. MAJOR BENEFIT: Better readability for complex cases, and potentially better performance relative to if statements. MAJOR DISADVANTAGE: Requires changes to compiler. ALTERNATIVES: It can currently be implemented with if statements. EXAMPLES Show us the code! SIMPLE EXAMPLE: Show the simplest possible program utilizing the new feature. switch (c) { case ['a'..'z']: return "lower case" ; case ['A'..'Z']: return "upper case" ; default: return "something else" ; } ADVANCED EXAMPLE: Show advanced usage(s) of the feature. switch (suit, value) { case [SPADE..CLUB], [2..10] : return "black low-value card" ; case [HEART..DIAMOND], [2..10] : return "red low-value card" ; case _, [11..14]: return "face card" ; } DETAILS SPECIFICATION: Describe how the proposal affects the grammar, type system, and meaning of expressions and statements in the Java Programming Language as well as any other known impacts. * The lexer will need to support underscore ('_') and ".." * The parser rules for switch statements must be changed. SwitchStatement: switch (Expression [, Expression]*) SwitchBlock SwitchLabel: case CaseExpressions : default : CaseExpressions: CaseExpression CaseExpressions , CaseExpression CaseExpression: _ ConstantExpression [ ConstantExpression .. ConstantExpression ] EnumConstantName [ EnumConstantName .. EnumConstantName ] * Semantic rules: - The number of CaseExpressions must equal the number of expressions in the SwitchStatement - The underscore ('_') means "don't care" - In [ c1 .. c2], c1 should be less than c2 - The types of the constants/enums must match the type of the expression in the same position - If the range of constants/enums overlap between case arms, then raise an error. COMPILATION: Simple desugaring transformations: ---------------------------------- switch (e1, e2) { case C1, C2: stmt1 ; case C3, _: stmt2 ; default: stmt3 ; } ==> x = e1 ; y = e2 ; switch (x) { case C1: switch (y) { case C2: stmt1 ; case C4: stmt2 ; default: stmt3 ; } break ; case C3: stmt2 ; break ; default: stmt3 ; } ----------------------------------- case [V1 .. Vn] : stmts ; ==> case V1: case V2: ... case Vn: stmts ; ----------------------------------- Both of these could blow up in code size. Therefore, a better implementation of the switch would compile down to gotos to the correct statement block. This is why proper compiler support would be nice. For case ranges, if the range is too big then turn into an if statement: "if (x >= V1 && x <= V2)". TESTING: How can the feature be tested? Normal compiler testing. LIBRARY SUPPORT: Are any supporting libraries needed for the feature? None REFLECTIVE APIS: Do any of the various and sundry reflection APIs need to be updated? This list of reflective APIs includes but is not limited to core reflection (java.lang.Class and java.lang.reflect.*), javax.lang.model.*, the doclet API, and JPDA. The reflection APIs will need to return a list of switch expressions and case constants. Also, new expression nodes must be added for ranges and for the "don't care" underscore. OTHER CHANGES: Do any other parts of the platform need be updated too? Possibilities include but are not limited to JNI, serialization, and output of the javadoc tool. Don't think so. MIGRATION: Sketch how a code base could be converted, manually or automatically, to use the new feature. I think this would be difficult because the logic would be obscured in if statements. COMPATIBILITY BREAKING CHANGES: Are any previously valid programs now invalid? If so, list one. None. EXISTING PROGRAMS: How do source and class files of earlier platform versions interact with the feature? Can any new overloadings occur? Can any new overriding occur? Should be backwards compatible. REFERENCES EXISTING BUGS: Please include a list of any existing Sun bug ids related to this proposal. URL FOR PROTOTYPE (optional): If there's interest, I can cook up a prototype with Polyglot. From schulz at e-Spirit.de Thu Mar 5 14:19:53 2009 From: schulz at e-Spirit.de (Schulz, Stefan) Date: Thu, 5 Mar 2009 23:19:53 +0100 Subject: PROPOSAL: Lightweight Properties References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com><200903051527.53497.david.goodenough@linkchoose.co.uk><28bca0ff0903050841n7751a3d0yfc268b408b071475@mail.gmail.com> <200903051709.46250.david.goodenough@linkchoose.co.uk> Message-ID: <7D2077BFF677D2429DDDEE095D9A48AC01FED3@osiris2.e-spirit.de> > I do not see (maybe I did not understand FCM) how I could handle > foo#bar#ali. In this case you need a Field array, not just a field. > Additionally the FCM case only seems to handle the Foo#bar case, > not the foo#bar case. That is not the end of the world - it would work > in the examples I need, but it is less than my proposal covers. Field literals as defined by FCM are meant to ease access for reflection. There was no further intent, AFAIR, as to have an analogue to Method literals. As the result is a Field instance, chaining does not make sense. Literals are only defined on types not instances. I'm not sure about autoconverting foo#bar to some Property instance. The main goal, as far as I understood, is to have compile time checks on accessing properties instead of using Strings. Not sure, if this helps, but just to note down the thought: As a prerequisite, we might need a generified Field class (not necessarily has to be the java.reflect.Field class). Now assuming Foo having a field bar of type Bar, and Bar having a field baz of type Baz. Using (generified) Field literals, one could create a property builder taking Fields instead of Strings as parameters, e.g.: Property p1 = PropertyBuilder.on(Foo.class).at(Foo#bar); Property p2 = PropertyBuilder.on(Foo.class).via(Foo#bar).at(Bar#baz); Property p3 = PropertyBuilder.on(foo).at(Foo#bar); Property p4 = PropertyBuilder.on(foo).via(Foo#bar).at(Bar#baz); I admit, this does not look as neat, but would serve the purpose. Or am I missing the target? Cheers, Stefan From tim at peierls.net Thu Mar 5 14:24:13 2009 From: tim at peierls.net (Tim Peierls) Date: Thu, 5 Mar 2009 17:24:13 -0500 Subject: PROPOSAL: fold keyword In-Reply-To: <17b2302a0903051328g5a98b084nd49d37339a0fa642@mail.gmail.com> References: <17b2302a0903051328g5a98b084nd49d37339a0fa642@mail.gmail.com> Message-ID: <63b4e4050903051424k5806158as698cfbf580bf6043@mail.gmail.com> Also check out ParallelArray, which is built on top of the ForkJoin framework proposed for Java 7: http://gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/ParallelArray.html The simple example becomes trivial: long sum = parallelLongArray.sum(); The more complex example that Josh mentioned would look like this: ParallelArray emps = ... // Salaries of employees not on vacation: return emps .withFilter(notPredicate(isOnVacation)) .withMapping(salaryField) .all(); where notPredicate is a static import from CommonOps, and isOnVacation and salaryField could be defined as: static final Predicate isOnVacation = new Predicate { public boolean op(Employee e) { return e.onVacation(); } }; static final Op salaryField = new Op { public BigDecimal op(Employee e) { return e.getSalary(); } }; These examples are likely to outperform the sequential versions on a multiprocessor for moderately large inputs. --tim On Thu, Mar 5, 2009 at 4:28 PM, Joshua Bloch wrote: > Gabriel, > > This doesn't seem compelling. > > Here's your simple example: > > // sum all numbers in the list > Integer sum = > fold(Integer n : list; // iterating collection element n > Integer result = 0) { // Where to accumulate the result, and > the initial value > result += n; > }; > } > > And here's how it looks today (with no change to the language or > libraries): > > Integer sum = 0; > for (Integer n : list) > sum += n; > > > Here's one of your complex examples: > > // returns a new collection with the salaries of the employees not on > vacation > List salaries = > fold(Employee e : emps; > List newList = new ArrayList()) { > if (!e.onVacation()) { > newList.add(e.getSalary()); > } > } > > And here's how it looks today: > > List salaries = new ArrayList(); > for (Employee e : emps) > if (!e.onVacation()) > salaries.add(e.getSalary()); > > To my eyes, the current version is clearer as well as shorter. > > Josh > > From reinier at zwitserloot.com Thu Mar 5 17:15:28 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 6 Mar 2009 02:15:28 +0100 Subject: PROPOSAL: Multiple switch expressions and case ranges In-Reply-To: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> References: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> Message-ID: This proposal does not appear to be complete. As you yourself mention, attempting to switch on [0 .. 1000000000] would generate an enormous class file. Also, your first desugaring example, which rewrites a multi-switch statement to nested switch statements, is certainly not a trivial operation. Where's the specification (and preferably some example code) on how the compiler is supposed to get from the sugar to the desugar? Perhaps this is an error in the Project Coin form, but all proposals should list chapter and verse of the JLS entries that need to be updated, which neccessarily includes a complete and detailed treatment on how the compiler is supposed to do the job. A single example desugaring isn't good enough. Any proposal that includes words like 'If XYZ is too big', is neccessarily not ready for this mailing list (as a proposal. It's fine as a request for comments and help). When does a range become too big? Could you explain the impact on size vs. lookup speed and make a solid recommendation for the right size to switch over? There's no need to update reflection APIs; you can't get at method code with them. You have to update the internal AST API, which you could list for completeness sake, but I don't think that's the intent of the Project Coin form (though, most proposals so far do mention it. I feel its not neccessary because 99% of all project coin proposals I can even think of require it. It's kind of implied when you say "Language Change Proposal"). JNI, the javadoc tool. I sort of like where this proposal is going, but as you yourself mentioned, the power of match/case in languages like Scala and Haskell is scary, and thus this proposal needs to be well aware of how java might some day get there, and be sure that we don't close future avenues early by screwing up now. I think this idea is probably out of scope, but I'll let Joe Darcy and friends be the judge of that. At the very least I would expect this system to work with Comparables, assuming the input and both range ends are all Comparable-compatible with each other (as provided by generics). Matching on type is also a relevant usecase in my opinion, so even if your proposal doesn't add it, you may want to include a rough sketch just to show that your syntax won't get in the way of a future expansion. --Reinier Zwitserloot On Mar 5, 2009, at 23:16, Pinku Surana wrote: > Has the switch statement in C languages evolved much since the '80s? > I'm > envious of the case/match expression in functional languages and > looking for > simple ways to make 'switch' more powerful. > > > > AUTHOR(S): Pinku Surana > > OVERVIEW > > FEATURE SUMMARY: > > Extend the switch statement to support multiple switch expressions > and case > ranges. > > MAJOR ADVANTAGE: > > It is syntactic sugar that makes it easier to write/read complex > logic. This is one small aspect of the vastly more powerful match or > case expression in functional languages. > > MAJOR BENEFIT: > > Better readability for complex cases, and potentially better > performance relative to if statements. > > MAJOR DISADVANTAGE: > > Requires changes to compiler. > > ALTERNATIVES: > > It can currently be implemented with if statements. > > EXAMPLES > > Show us the code! > > SIMPLE EXAMPLE: Show the simplest possible program utilizing the new > feature. > > switch (c) { > case ['a'..'z']: return "lower case" ; > case ['A'..'Z']: return "upper case" ; > default: return "something else" ; > } > > ADVANCED EXAMPLE: Show advanced usage(s) of the feature. > > switch (suit, value) { > case [SPADE..CLUB], [2..10] : return "black low-value card" ; > case [HEART..DIAMOND], [2..10] : return "red low-value card" ; > case _, [11..14]: return "face card" ; > } > > DETAILS > > SPECIFICATION: Describe how the proposal affects the grammar, type > system, > and meaning of expressions and statements in the Java Programming > Language > as well as any other known impacts. > > * The lexer will need to support underscore ('_') and ".." > * The parser rules for switch statements must be changed. > > SwitchStatement: > switch (Expression [, Expression]*) SwitchBlock > > SwitchLabel: > case CaseExpressions : > default : > > CaseExpressions: > CaseExpression > CaseExpressions , CaseExpression > > CaseExpression: > _ > ConstantExpression > [ ConstantExpression .. ConstantExpression ] > EnumConstantName > [ EnumConstantName .. EnumConstantName ] > > * Semantic rules: > - The number of CaseExpressions must equal the number of > expressions in > the SwitchStatement > - The underscore ('_') means "don't care" > - In [ c1 .. c2], c1 should be less than c2 > - The types of the constants/enums must match the type of the > expression > in the same position > - If the range of constants/enums overlap between case arms, then > raise an > error. > > COMPILATION: > > Simple desugaring transformations: > > ---------------------------------- > switch (e1, e2) { > case C1, C2: stmt1 ; > case C3, _: stmt2 ; > default: stmt3 ; > } > ==> > x = e1 ; > y = e2 ; > switch (x) { > case C1: switch (y) { > case C2: stmt1 ; > case C4: stmt2 ; > default: stmt3 ; > } > break ; > case C3: stmt2 ; > break ; > default: stmt3 ; > } > ----------------------------------- > case [V1 .. Vn] : stmts ; > ==> > case V1: > case V2: > ... > case Vn: stmts ; > ----------------------------------- > > > Both of these could blow up in code size. Therefore, a better > implementation of the switch would compile down to gotos to the > correct statement block. This is why proper compiler support would > be nice. > > For case ranges, if the range is too big then turn into an if > statement: > "if (x >= V1 && x <= V2)". > > > TESTING: How can the feature be tested? > > Normal compiler testing. > > LIBRARY SUPPORT: Are any supporting libraries needed for the feature? > > None > > REFLECTIVE APIS: Do any of the various and sundry reflection APIs > need to be > updated? This list of reflective APIs includes but is not limited to > core > reflection (java.lang.Class and java.lang.reflect.*), > javax.lang.model.*, > the doclet API, and JPDA. > > The reflection APIs will need to return a list of switch expressions > and case constants. Also, new expression nodes must be added for > ranges and for the "don't care" underscore. > > OTHER CHANGES: Do any other parts of the platform need be updated too? > Possibilities include but are not limited to JNI, serialization, and > output > of the javadoc tool. > > Don't think so. > > MIGRATION: Sketch how a code base could be converted, manually or > automatically, to use the new feature. > > I think this would be difficult because the logic would be obscured > in if > statements. > > COMPATIBILITY > > BREAKING CHANGES: Are any previously valid programs now invalid? If > so, list > one. > > None. > > EXISTING PROGRAMS: How do source and class files of earlier platform > versions interact with the feature? Can any new overloadings occur? > Can any > new overriding occur? > > Should be backwards compatible. > > REFERENCES > > EXISTING BUGS: Please include a list of any existing Sun bug ids > related to > this proposal. > > URL FOR PROTOTYPE (optional): > > If there's interest, I can cook up a prototype with Polyglot. > From crazybob at crazybob.org Thu Mar 5 17:30:00 2009 From: crazybob at crazybob.org (Bob Lee) Date: Thu, 5 Mar 2009 17:30:00 -0800 Subject: PROPOSAL: Simplified Varargs Method Invocation Message-ID: Simplified Varargs Method Invocation AUTHOR: Bob Lee *OVERVIEW * FEATURE SUMMARY: When a programmer tries to invoke a *varargs* (variable arity) method with a non-reifiable varargs type, the compiler currently generates an "unsafe operation" warning. This proposal moves the warning from the call site to the method declaration. MAJOR ADVANTAGE: Safely and significantly reduces the total number of warnings reported to and suppressed by programmers. Reduces programmer confusion. Enables API designers to use varargs. MAJOR BENEFIT: Plugs a leaky abstraction. Creating an array when you call a varargs method is an implementation detail that we needn't expose to users. Addresses a well known "gotcha" encountered when you mix varargs and generics. Most programmers are surprised to find out you can only clear this warning by suppressing it (especially considering we introduced varargs and generics in the same language update); they waste time looking for alternatives that don't exist. Google Code Search finds almost 90k callers of Arrays.asList() (http://tinyurl.com/dept4d). We could safely suppress the warning once and for all on asList()'s declaration instead of unnecessarily warning every caller that uses a non-reifiable type. MAJOR DISADVANTAGE: The compiler will generate a warning for a method declaration whether or not someone actually calls the method with a non-reifiable type. Allows loss of type safety if the varargs method suppresses the warning and uses the varargs array unsafely. ALTERNATIVES: a) Don't mix varargs with generics. Use the more verbose and less straightforward but warning-free builder pattern. Most API designers choose this route. b) Improve the warning message. Current message: "uses unchecked or unsafe operations" c) Reify generics. d) Introduce a second varargs syntax (perhaps using "...." instead of "...") that uses List instead of T[]. e) Defile the type system. Note: This proposal doesn't preclude any of these other approaches. *EXAMPLES * Before this change: static List asList(T... elements) { ... } static List> stringFactories() { Callable a, b, c; ... *// Warning: **"uses unchecked or unsafe operations"* return asList(a, b, c); } After this change: *// Warning: **"enables unsafe generic array creation"* static List asList(T... elements) { ... } static List> stringFactories() { Callable a, b, c; ... return asList(a, b, c); } If asList() prohibits storing elements that aren't of type T in the elements array, we can safely suppress the warning: *@SuppressWarnings("generic-varargs") // Ensures only values of type T can be stored in elements. * static List asList(T... elements) { ... } *DETAILS * SPECIFICATION: When compiling code that calls a varargs method with a non-reifiable varargs element type, if the target method was compiled targeting Java 7 or later, the compiler needn't generate a warning for the caller. When compiling a varargs method that could accept a non-reifiable varargs type, the compiler should generate a warning on the varargs method declaration. A varargs type is non-reifiable if it contains a type variable anywhere in its signature. For a varargs argument of type T, the programmer can safely suppress the warning using @SuppressWarnings("generic-varargs") so long as the varargs method ensures that only elements of type T can be stored in the varargs array. COMPILATION: Tools should no longer generate a warning for varargs method callers. Instead, they should generate a warning for varargs method declarations that support non-reifiable types. TESTING: Compile test programs and ensure that the compiler generates the expected warnings. LIBRARY SUPPORT: Suppress warnings on the following varargs methods in the JDK: - Arrays.asList(T... a) - Collections.addAll(Collection c, T... elements) - EnumSet.of(E first, E... rest) REFLECTIVE APIS: n/a OTHER CHANGES: n/a MIGRATION: Existing callers may be able to remove @SuppressWarnings("unchecked") from their code. Existing libraries should add @SuppressWarnings("generic-varargs") to methods with signatures containing non-reifiable varargs types. *COMPATIBILITY * BREAKING CHANGES: None EXISTING PROGRAMS: If you recompile an existing program with "-target 7", the compiler will generate warnings for method declarations containing non-reifiable varargs types. *REFERENCES * EXISTING BUGS: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6227971 JLS Section 15.12.4.2 "Evaluate Arguments" ( http://java.sun.com/docs/books/jls/third_edition/html/expressions.html) "If the method being invoked is a variable arity method (?8.4.1)m, it necessarily has n>0 formal parameters. The final formal parameter of m necessarily has type T[] for some T, and m is necessarily being invoked with k0 actual argument expressions. If m is being invoked with kn actual argument expressions, or, if m is being invoked with k=n actual argument expressions and the type of the kth argument expression is not assignment compatible with T[], then the argument list (e1, ... , en-1, en, ...ek) is evaluated as if it were written as (e1, ..., en-1, new T[]{en, ..., ek}). The argument expressions (possibly rewritten as described above) are now evaluated to yield argument values. Each argument value corresponds to exactly one of the method's n formal parameters." Angelika Langer's Java Generics FAQ, "Why does the compiler sometimes issue an unchecked warning when I invoke a 'varargs' method?" ( http://tinyurl.com/8w2dk) Josh Bloch's "Effective Java" 2nd Edition, page 120 ( http://tinyurl.com/chtgbd) Alex Miller's blog, "Generics puzzler - array construction" ( http://tech.puredanger.com/2007/02/27/generics-array-construction/) "Java Generic and Collections", page 95 (http://tinyurl.com/c53pnu) From Joe.Darcy at Sun.COM Thu Mar 5 18:03:34 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Thu, 05 Mar 2009 18:03:34 -0800 Subject: PROPOSAL: Multiple switch expressions and case ranges In-Reply-To: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> References: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> Message-ID: <49B08476.8090706@sun.com> Pinku Surana wrote: > Has the switch statement in C languages evolved much since the '80s? I'm > envious of the case/match expression in functional languages and looking for > simple ways to make 'switch' more powerful. > > > > AUTHOR(S): Pinku Surana > > OVERVIEW > > FEATURE SUMMARY: > > Extend the switch statement to support multiple switch expressions and case > ranges. > [snip] > EXISTING BUGS: Please include a list of any existing Sun bug ids related to > this proposal. > > The Sun bug database has bugs in this area. -Joe From philvarner at gmail.com Thu Mar 5 20:50:26 2009 From: philvarner at gmail.com (Phil Varner) Date: Thu, 5 Mar 2009 20:50:26 -0800 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: <49AF15DC.20408@gmail.com> References: <49AF1114.3080205@sun.com> <49AF15DC.20408@gmail.com> Message-ID: > Static import was surprising complicated in JDK 5. While these aliases could alleviate some problems, I think they would be easily abused > and even when not being abused render code less readable. > IMO, having alternate names for potentially common classes would be less readable. I agree for common classes this could be a problem, but I don't think it would be any less of a problem than the existing support for wildcards. I see this more as a solution targeted mostly for long package names with overlapping class names. I'm going to need to think some about what "readable" really means, and would be interested in any thoughts on this topic. > While grammar changes are part of the picture, the substantive changes would be to JLSv3 section 6.5 "Determining the Meaning of a Name": Thanks for pointing this out, it's definitely a huge hole in the proposal. > The Javapolis discussions of 2007 ended with the majority of > participants choosing against aliasing of imports (typedefs). > > http://www.javapolis.com/confluence/plugins/advanced/gallery-slideshow.action?pageId=32793&decorator=popup&imageNumber=9 Thanks for the pointer. I, too, would probably vote against a the proposal of import Map as CodeValueMap; Several of the related bugs mention this syntax, but I think this combines two issues together. It seems to me that the simple mapping of a fully-qualified class name to a "short" name is separate from the typedefing of a specifically-parameterized generified type to a short name. --Phil -- Machines might be interesting, but people are fascinating. -- K.P. From reinier at zwitserloot.com Thu Mar 5 21:39:06 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 6 Mar 2009 06:39:06 +0100 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: References: Message-ID: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> Heh, that was the next proposal I was going to write. (Apologies for a long and technically complicated post. I've rewritten it several times in an attempt to get to the point faster, but this is the best I can do). It really pains me to rain on your parade. I was doing some experimenting and found an admittedly very unlikely scenario that isn't backwards compatible. Then I realized, that this is actually (arguably) a bug, or at least a severe misfeature in javac right now! Therefore, this proposal should fix this problem as well. Of all proposals so far, I rate this one the highest, because it causes so much confusion and is closer to a bug in javac than a language feature, so I would be very happy if this proposal can be fully ironed out. Complete code showing the problem - copy and paste into Main.java, compile, and run: ------ import java.util.*; class Foo { public void foo(T... t) {} } class Bar extends Foo { //de-varargsing? Why is this legal? public void foo(String[] t) { System.out.println(t.getClass().getComponentType()); } } public class Main { public static void main(String[] args) { Foo f = new Bar(); List l = Arrays.asList("a", "b", "c"); bar(f, l); } public static void bar(Foo f, List l) { f.foo(l.get(0), l.get(1), l.get(2)); } } ----- The result is an error: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; Right now, you get the usual varargs warning, but nothing else at compile time. At runtime, you get the above error. The real bug here is the ability for any subclass to de-varargs a parameter. This bit has nothing to do with the proposal, other than that it so happens to deal with varargs. De-varargsing a parameter is somewhat similar to a subclass tightening the type of an overriden parameter, which isn't legal / gives you a different method altogether instead of overriding. If you really want to pass varargs into such a method, then the only solution is to cast the object to a less specific type, and then all of a sudden it works. In other words, this can happen, right now, in java 1.5/1.6: SubType s = new SubType(); s.foo(a, b, c); //method not found. SuperType st = s; st.foo(a, b, c); //no problem. I say that's a bug. The more serious problem, and one directly related to the proposal, is trying to reify a superclass's array type. (the subclass in the example above turning Foo's T into a reified 'String'). This action is fundamentally broken, and yet there's no way to avoid it. You can't effectively override a method of a superclass containing a generics type as an array's component type if you reified that generics parameter. You can try, but many callers simply can't call your method anymore. Right now, in java 1.5/1.6, you do get that generics warning Bob Lee's proposal is trying to move to the callee site, though it's not very informative and there's absolutely nothing a caller can do whatsoever. If Bob Lee's proposal is implemented, the warning just as useless, and arguably skipped even faster than it is now. Specifically, you can't: A: widen the type of the parameter in the overriding method's signature to Object[] or Object..., as javac will refuse to compile it due to two different signatures erasing to the same signature. B: add a bogus type and use that T. Javac will compile it, but the signature of that method is then foo(String[]), and thus its a completely separate method, that doesn't override parent's foo method. Therefore, addendum #1 to this proposal: Generate more warnings. A. If you are overriding a method where in your signature an array is not varargsed, but in any of your supertypes' signatures, it is varargsed. This warning should be very severe as well and suggest in no uncertain terms that you NEED to replace your [] with "..."; optimally this is a compile time error, but fixing this now wouldn't be migration compatible. This warning should not show up if using - source 1.4 or lower, for obvious reasons. B. If you are overriding a method where in your signature an array type's component type has been reified compared to any of your supertypes' signatures for this method. The warning should explain that there's no work-around, but that anybody treating your instance as a type of (X) will likely get a runtime error if they tried to call this method. The only fix I can think of is to rejigger the signatures somehow: The method should signature as an Object[] same as parent, but javac should NOT consider this a separate method that erases to the same signature - it IS intended as the same method. If this is done, the warning on the method should be translated to something along the lines of Bob Lee's proposed warning (the actual component type of the array, if asked for at reification, isn't neccessarily correct, and your string array might all of a sudden give you integers if the caller handed you a generics-tainted array). A second addendum I would strongly urge is to use escape detection to eliminate the warning on the var-args-using methods. The following operations are all entirely safe, and they are also the only ones used by every single varargs method I've ever laid my eyes on, except Arrays.asList: Safe #1: Ask for the vararg array's length. Obviously safe - length has no relation to the array's type. Safe #2: Member lookup (array[index]). The type of a member lookup is entirely dependent on the compile-time type. The caller needs to worry about that compile-time type too, so can't stuff mistyped things in that varargs array without triggering a generics warning of their own. Once somebody somewhere gets a generics warning, any resulting ClassCastExceptions are acceptable (that's the status quo now, after all). Non-generified lookups such as the example above can't even run, because the method invocation itself will already blow up. This is bad, but it happens now too. Safe #3: foreaching through a varargs parameter. foreaching a combination of .length and member lookups, so by induction is obviously as safe as #1 and #2. Anything else, -anything- at all, including using it in any expression (other than the safe forms above), storing it into another variable or field, using it as a parameter to another method, or calling any other property on it, including toString() (there's no point in calling toString() on an array anyway, so why bother declaring that safe?) - is unsafe, and would generate the warning. The warning is then not generated on the var-args-accepting-method's signature, but instead on the first node in that method's AST that does something that isn't safe to the varargs parameter. The only borderline cases where the above preconditions are broken is Arrays.asList, which is a unique exception, and varargs methods that pass the entire varargs parameter to a helper method. It might be possible to declare passing varargs parameters to another method that also takes varargs as safe, but I'm not 100% certain that's always safe (as safe as generics are going to be in a non-reified world, that is). Note that for most of these cases, there are mixed-version problems. New code that calls into old code means nobody gets any warnings. I'm not sure if Bob's proposal includes this, but the compiler should continue to generate warnings on the site of the caller if the class file format of the targeted method goes with javac v1.6 or below. If a code-base starts mixing generated class files, things get even worse; methods that, during compile-time, weren't overriding anything, are suddenly supposed to override a generics or varargs based superclass because just the superclass has been recompiled with changes, for example. The only argument I can give in favour of this proposal is that doing that sort of thing already breaks a number of apparent invariants and can give you NoSuchMethodErrors and the like. --Reinier Zwitserloot On Mar 6, 2009, at 02:30, Bob Lee wrote: > Simplified Varargs Method Invocation > AUTHOR: Bob Lee > > *OVERVIEW > * > FEATURE SUMMARY: When a programmer tries to invoke a *varargs* > (variable > arity) method with a non-reifiable varargs type, the compiler > currently > generates an "unsafe operation" warning. This proposal moves the > warning > from the call site to the method declaration. > > MAJOR ADVANTAGE: Safely and significantly reduces the total number of > warnings reported to and suppressed by programmers. Reduces programmer > confusion. Enables API designers to use varargs. > > MAJOR BENEFIT: Plugs a leaky abstraction. Creating an array when you > call a > varargs method is an implementation detail that we needn't expose to > users. > Addresses a well known "gotcha" encountered when you mix varargs and > generics. Most programmers are surprised to find out you can only > clear this > warning by suppressing it (especially considering we introduced > varargs and > generics in the same language update); they waste time looking for > alternatives that don't exist. Google Code Search finds almost 90k > callers > of Arrays.asList() (http://tinyurl.com/dept4d). We could safely > suppress the > warning once and for all on asList()'s declaration instead of > unnecessarily > warning every caller that uses a non-reifiable type. > > MAJOR DISADVANTAGE: The compiler will generate a warning for a method > declaration whether or not someone actually calls the method with a > non-reifiable type. Allows loss of type safety if the varargs method > suppresses the warning and uses the varargs array unsafely. > > ALTERNATIVES: > a) Don't mix varargs with generics. Use the more verbose and less > straightforward but warning-free builder pattern. Most API designers > choose > this route. > b) Improve the warning message. Current message: "uses unchecked or > unsafe > operations" > c) Reify generics. > d) Introduce a second varargs syntax (perhaps using "...." instead of > "...") that uses List instead of T[]. > e) Defile the type system. > > Note: This proposal doesn't preclude any of these other approaches. > > *EXAMPLES > * > Before this change: > > static List asList(T... elements) { ... } > > static List> stringFactories() { > Callable a, b, c; > ... > *// Warning: **"uses unchecked or unsafe operations"* > return asList(a, b, c); > } > > After this change: > > *// Warning: **"enables unsafe generic array creation"* > static List asList(T... elements) { ... } > > static List> stringFactories() { > Callable a, b, c; > ... > return asList(a, b, c); > } > > If asList() prohibits storing elements that aren't of type T in the > elements > array, we can safely suppress the warning: > > *@SuppressWarnings("generic-varargs") > // Ensures only values of type T can be stored in elements. > * static List asList(T... elements) { ... } > > *DETAILS > * > SPECIFICATION: When compiling code that calls a varargs method with a > non-reifiable varargs element type, if the target method was compiled > targeting Java 7 or later, the compiler needn't generate a warning > for the > caller. When compiling a varargs method that could accept a non- > reifiable > varargs type, the compiler should generate a warning on the varargs > method > declaration. A varargs type is non-reifiable if it contains a type > variable > anywhere in its signature. For a varargs argument of type T, the > programmer > can safely suppress the warning using @SuppressWarnings("generic- > varargs") > so long as the varargs method ensures that only elements of type T > can be > stored in the varargs array. > > COMPILATION: Tools should no longer generate a warning for varargs > method > callers. Instead, they should generate a warning for varargs method > declarations that support non-reifiable types. > > TESTING: Compile test programs and ensure that the compiler > generates the > expected warnings. > > LIBRARY SUPPORT: Suppress warnings on the following varargs methods > in the > JDK: > - Arrays.asList(T... a) > - Collections.addAll(Collection c, T... elements) > - EnumSet.of(E first, E... rest) > > REFLECTIVE APIS: n/a > > OTHER CHANGES: n/a > > MIGRATION: Existing callers may be able to remove > @SuppressWarnings("unchecked") from their code. Existing libraries > should > add @SuppressWarnings("generic-varargs") to methods with signatures > containing non-reifiable varargs types. > > *COMPATIBILITY > * > BREAKING CHANGES: None > > EXISTING PROGRAMS: If you recompile an existing program with "- > target 7", > the compiler will generate warnings for method declarations containing > non-reifiable varargs types. > > *REFERENCES > * > EXISTING BUGS: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6227971 > > JLS Section 15.12.4.2 "Evaluate Arguments" ( > http://java.sun.com/docs/books/jls/third_edition/html/ > expressions.html) > > "If the method being invoked is a variable arity method > (?8.4.1) >m, > it necessarily has n>0 formal parameters. The final formal parameter > of m > necessarily has type T[] for some T, and m is necessarily being > invoked with > k0 actual argument expressions. > > If m is being invoked with kn actual argument expressions, or, if m > is being > invoked with k=n actual argument expressions and the type of the kth > argument expression is not assignment compatible with T[], then the > argument > list (e1, ... , en-1, en, ...ek) is evaluated as if it were written > as (e1, > ..., en-1, new T[]{en, ..., ek}). > > The argument expressions (possibly rewritten as described above) are > now > evaluated to yield argument values. Each argument value corresponds to > exactly one of the method's n formal parameters." > > Angelika Langer's Java Generics FAQ, "Why does the compiler > sometimes issue > an unchecked warning when I invoke a 'varargs' method?" ( > http://tinyurl.com/8w2dk) > > Josh Bloch's "Effective Java" 2nd Edition, page 120 ( > http://tinyurl.com/chtgbd) > > Alex Miller's blog, "Generics puzzler - array construction" ( > http://tech.puredanger.com/2007/02/27/generics-array-construction/) > > "Java Generic and Collections", page 95 (http://tinyurl.com/c53pnu) > From develop4lasu at gmail.com Thu Mar 5 22:40:33 2009 From: develop4lasu at gmail.com (=?UTF-8?Q?Marek_Kozie=C5=82?=) Date: Fri, 6 Mar 2009 07:40:33 +0100 Subject: PROPOSAL: Multiple switch expressions and case ranges In-Reply-To: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> References: <30992e5d0903051416o446a9363kc7ac403510c3f6b7@mail.gmail.com> Message-ID: <28bca0ff0903052240v754328ceief2f2ff6ac738500@mail.gmail.com> Hi. I hoped that no one will be interested in this solution (but I was wrong). Extending switch is no problem for me, but why so partially? Let's see some switch construction that would allow to handle any object (inluding null-s) and keep encapsulation as well: >Base Interfaces: public interface Equally { /** * @return true if objects are equal */ boolean equal(Type object, Type other); } public interface EquallyAsymmetric { /** * @return true if objects are equal */ boolean equal(Source source, Target target); } // Same as Comparator but allow encapsulation public interface ComparatorAsymmetric { int compare(Source source, Target target); } Switch: switch ( Expression : Equally) SwitchBlock switch ( Expression : EquallyAsymmetric) SwitchBlock switch ( Expression : Comparator) SwitchBlock switch ( Expression : ComparatorAsymmetric) SwitchBlock switch ( Expression : null) SwitchBlock // for natural order >How would that work? public class SomeData { public SomeData(String key, Data data) { super(); this.key = key; this.data = data; // validation } private Data data; public final String key; public final static Equally equally = new EquallySomeData(); public final static EquallyAsymmetric equallyAsymmetric = new EquallyAsymmetricSomeData(); ; public final static Comparator comparator = new ComparatorSomeData(); private static class ComparatorSomeData implements Comparator { @Override public int compare(SomeData o1, SomeData o2) { return o1.key.compareTo(o2.key); } }; private static class EquallyAsymmetricSomeData implements EquallyAsymmetric { @Override public boolean equal(SomeData source, String target) { return source.key.equals(target); } }; private static class EquallySomeData implements Equally { @Override public boolean equal(SomeData object, SomeData other) { return object.key.equals(other.key); } } } Equally sample: SomeData getMatch(String key) { switch (new SomeData(key,null):SomeData.equally) { case someData: break; default: break; } } Equally asymmetric sample: SomeData getMatch(String key) { switch (new SomeData(key,null):SomeData.equallyAsymmetric ) { case ?some?: break; default: break; } } Comparator sample: SomeData getMatch(String key) { switch (new SomeData(key,null):SomeData.equallyAsymmetric ) { case lower <= ... < upper, special: break; default: break; } } Notice that if you want ranges in case soon or later o will need relations: <=, >=, <, >, because there is no (""-1), I know there is workaround but as I think there is no need to put solution which require new workarounds. >WORKAROUND: enum Switch { ONE("asd") { @Override public void action() { System.out.println(this.text); } },// TWO("bad");// protected String text; public void action() { throw new NotImplementedException(); } Switch(String text) { if (text == null) { throw new NullPointerException("text"); } this.text = text; } public static Switch getByText(String text) { if (text == null) return null; for (Switch casee : Switch.values()) { if (casee.text.equals(text)) return casee; } return null; } public static Switch getByTextForStartWith(String prefix) { if (prefix == null) return null; for (Switch casee : Switch.values()) { if (casee.text.startsWith(prefix)) return casee; } return null; } } REFERENCES: http://bugs.sun.com/view_bug.do?bug_id=5012262 http://lasu2string.blogspot.com/2008/12/string-switch-small-language-changes-on.html -- Pozdrowionka. / Regards. Lasu aka Marek Kozie? http://lasu2string.blogspot.com/ From crazybob at crazybob.org Fri Mar 6 00:02:25 2009 From: crazybob at crazybob.org (Bob Lee) Date: Fri, 6 Mar 2009 00:02:25 -0800 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> References: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> Message-ID: On Thu, Mar 5, 2009 at 9:39 PM, Reinier Zwitserloot wrote: > (Apologies for a long and technically complicated post. I've rewritten > it several times in an attempt to get to the point faster, but this is > the best I can do). > Not at all. This is great. Thanks for the feedback, Reinier! Right now, you get the usual varargs warning, but nothing else at > compile time. At runtime, you get the above error. > I get this warning on Bar.foo(String[]): "cannot override foo(T...) in Foo; overriding method is missing '...'" I get a similar warning when I try to override an array method with a varargs method. > The more serious problem, and one directly related to the proposal, is > trying to reify a superclass's array type. (the subclass in the > example above turning Foo's T into a reified 'String'). This action is > fundamentally broken, and yet there's no way to avoid it. You can't > effectively override a method of a superclass containing a generics > type as an array's component type if you reified that generics > parameter. You can try, but many callers simply can't call your method > anymore. Right now, in java 1.5/1.6, you do get that generics warning > Bob Lee's proposal is trying to move to the callee site, though it's > not very informative and there's absolutely nothing a caller can do > whatsoever. If Bob Lee's proposal is implemented, the warning just as > useless, and arguably skipped even faster than it is now. > > Specifically, you can't: > > A: widen the type of the parameter in the overriding method's > signature to Object[] or Object..., as javac will refuse to compile it > due to two different signatures erasing to the same signature. > > B: add a bogus type and use that T. Javac will > compile it, but the signature of that method is then foo(String[]), > and thus its a completely separate method, that doesn't override > parent's foo method. > Good catch. I hadn't thought about this. It would be nice if javac could just erase to Object[] in the overridding method, but I can't say whether or not that's a viable option. Looks like I have some investigation ahead of me. A second addendum I would strongly urge is to use escape detection to > eliminate the warning on the var-args-using methods. The following > operations are all entirely safe, and they are also the only ones used > by every single varargs method I've ever laid my eyes on, except > Arrays.asList: > This is what I meant by alternative e) defile the type system. :-) Basically, you can always just store the varargs value in an Object variable. When I discussed this with Alex Buckley, he found generating a warning in this case too distastful. On the bright side, this warning only turns up 3 times in the entire JDK, so it's probably best to keep the proposal simple. Note that for most of these cases, there are mixed-version problems. > New code that calls into old code means nobody gets any warnings. I'm > not sure if Bob's proposal includes this, but the compiler should > continue to generate warnings on the site of the caller if the class > file format of the targeted method goes with javac v1.6 or below. > The proposal covers this in the spec: "if the target method was compiled targeting Java 7 or later" Bob From forax at univ-mlv.fr Fri Mar 6 00:28:38 2009 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Fri, 06 Mar 2009 09:28:38 +0100 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> References: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> Message-ID: <49B0DEB6.4010308@univ-mlv.fr> Reinier Zwitserloot a ?crit : > Heh, that was the next proposal I was going to write. > > (Apologies for a long and technically complicated post. I've rewritten > it several times in an attempt to get to the point faster, but this is > the best I can do). > > It really pains me to rain on your parade. I was doing some > experimenting and found an admittedly very unlikely scenario that > isn't backwards compatible. Then I realized, that this is actually > (arguably) a bug, or at least a severe misfeature in javac right now! > Therefore, this proposal should fix this problem as well. Of all > proposals so far, I rate this one the highest, because it causes so > much confusion and is closer to a bug in javac than a language > feature, so I would be very happy if this proposal can be fully ironed > out. > > Complete code showing the problem - copy and paste into Main.java, > compile, and run: > > ------ > > import java.util.*; > > class Foo { > public void foo(T... t) {} > } > > class Bar extends Foo { > //de-varargsing? Why is this legal? > Because you want to be able to replace an array with a varargs in library without creating errors in code that use that library. > public void foo(String[] t) { > System.out.println(t.getClass().getComponentType()); > } > } > > public class Main { > public static void main(String[] args) { > Foo f = new Bar(); > List l = Arrays.asList("a", "b", "c"); > bar(f, l); > } > > public static void bar(Foo f, List l) { > f.foo(l.get(0), l.get(1), l.get(2)); > } > } > > ----- > > The result is an error: > > Exception in thread "main" java.lang.ClassCastException: > [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; > > Right now, you get the usual varargs warning, but nothing else at > compile time. At runtime, you get the above error. > Warnings in Java are not like in C, it means something will go wrong :) the call: f.foo(l.get(0), l.get(1), l.get(2)); generate a warning because you are creating an arry of parameterized type (a Foo[]) which are "inherently unsafe" to quote gilad bracha. > The real bug here is the ability for any subclass to de-varargs a > parameter. No [...] See: >> Angelika Langer's Java Generics FAQ, "Why does the compiler >> sometimes issue >> an unchecked warning when I invoke a 'varargs' method?" ( >> http://tinyurl.com/8w2dk) >> R?mi From david.goodenough at linkchoose.co.uk Fri Mar 6 01:47:22 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Fri, 6 Mar 2009 09:47:22 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <7D2077BFF677D2429DDDEE095D9A48AC01FED3@osiris2.e-spirit.de> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903051709.46250.david.goodenough@linkchoose.co.uk> <7D2077BFF677D2429DDDEE095D9A48AC01FED3@osiris2.e-spirit.de> Message-ID: <200903060947.24239.david.goodenough@linkchoose.co.uk> On Thursday 05 March 2009, Schulz, Stefan wrote: > > I do not see (maybe I did not understand FCM) how I could handle > > foo#bar#ali. In this case you need a Field array, not just a field. > > Additionally the FCM case only seems to handle the Foo#bar case, > > not the foo#bar case. That is not the end of the world - it would work > > in the examples I need, but it is less than my proposal covers. > > Field literals as defined by FCM are meant to ease access for reflection. > There was no further intent, AFAIR, as to have an analogue to Method > literals. As the result is a Field instance, chaining does not make sense. > Literals are only defined on types not instances. > > I'm not sure about autoconverting foo#bar to some Property instance. The > main goal, as far as I understood, is to have compile time checks on > accessing properties instead of using Strings. Not sure, if this helps, but > just to note down the thought: > > As a prerequisite, we might need a generified Field class (not necessarily > has to be the java.reflect.Field class). Now assuming Foo having a field > bar of type Bar, and Bar having a field baz of type Baz. Using (generified) > Field literals, one could create a property builder taking Fields instead > of Strings as parameters, e.g.: > > Property p1 = PropertyBuilder.on(Foo.class).at(Foo#bar); > Property p2 = > PropertyBuilder.on(Foo.class).via(Foo#bar).at(Bar#baz); Property > p3 = PropertyBuilder.on(foo).at(Foo#bar); > Property p4 = PropertyBuilder.on(foo).via(Foo#bar).at(Bar#baz); > > I admit, this does not look as neat, but would serve the purpose. Or am I > missing the target? > > Cheers, > Stefan Yes it would server the purpose, and frankly ease of use is trumped by desparate need so I am happy to take any compiler checkable solution that works. In effect the Property class becomes the generified Field object, so that problem is circumvented. The only thing it can not do is to check that the chain is correct (i.e in the example above that Foo#bar is a Bar( at compile time. When the PropertyBuilding is building the Property it can, but that is a little later than I would like - but still a great improvement on evalutation time, added to which the chained case is a minority case. My only question concerns annotations. It is important that the Field object is the real one, and not a synthetic partial copy. The reason for this is so that I can access Annotations. If this will work then I am happy. So if FCM is going to be in -7 then my proposal is unnecessary. But of course that makes an assumption and unless I have missed something it seemed to be as far off as Property support. David From schulz at e-Spirit.de Fri Mar 6 02:07:14 2009 From: schulz at e-Spirit.de (Schulz, Stefan) Date: Fri, 6 Mar 2009 11:07:14 +0100 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903060947.24239.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com><200903051709.46250.david.goodenough@linkchoose.co.uk><7D2077BFF677D2429DDDEE095D9A48AC01FED3@osiris2.e-spirit.de> <200903060947.24239.david.goodenough@linkchoose.co.uk> Message-ID: <7D2077BFF677D2429DDDEE095D9A48AC105DEECA@osiris2.e-spirit.de> > In effect the Property class becomes the generified Field > object, so that > problem is circumvented. Well, the generified Field object should be returned by the reference, so that the generic type can be retrieved at compile-time, otherwise it would not make much sense. That's why the example uses the factory method at(), otherwise it will be difficult to have compile time type safety. > The only thing it can not do is to check that the chain is > correct (i.e in the > example above that Foo#bar is a Bar( at compile time. When the > PropertyBuilding is building the Property it can, but that > is a little later > than I would like - but still a great improvement on > evalutation time, added > to which the chained case is a minority case. You are right. I forgot about the correctness of the chain. And this will only be possible by a new notation. > My only question concerns annotations. It is important that > the Field object > is the real one, and not a synthetic partial copy. The > reason for this is > so that I can access Annotations. If this will work then I am happy. I don't understand this one. You won't annotate the Field class but the field, so the object returned will have to support Annotation retrieval, I guess. > So if FCM is going to be in -7 then my proposal is > unnecessary. But of course > that makes an assumption and unless I have missed something it seemed > to be as far off as Property support. FCM won't. But maybe a proposal for Field-Literals might have a chance, as it seems a coin to me. Not much magic about it, I think. But then again, I might miss the hard parts as I have no real insight into javac etc. @Joe: Would it make sense to file a proposal on Field-Literals or would it be doomed right away? And I am not sure, whether completing such a proposal by Method- and Constructor-Literals would become too big for Coin. Any hint? Further, I am not sure, how elaborate I could do it by myself, too, so any coop is welcome. Sorry, for getting off topic. Cheers, Stefan From david.goodenough at linkchoose.co.uk Fri Mar 6 02:10:38 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Fri, 6 Mar 2009 10:10:38 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <200903060947.24239.david.goodenough@linkchoose.co.uk> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <7D2077BFF677D2429DDDEE095D9A48AC01FED3@osiris2.e-spirit.de> <200903060947.24239.david.goodenough@linkchoose.co.uk> Message-ID: <200903061010.40646.david.goodenough@linkchoose.co.uk> On Friday 06 March 2009, David Goodenough wrote: > On Thursday 05 March 2009, Schulz, Stefan wrote: > > > I do not see (maybe I did not understand FCM) how I could handle > > > foo#bar#ali. In this case you need a Field array, not just a field. > > > Additionally the FCM case only seems to handle the Foo#bar case, > > > not the foo#bar case. That is not the end of the world - it would work > > > in the examples I need, but it is less than my proposal covers. > > > > Field literals as defined by FCM are meant to ease access for reflection. > > There was no further intent, AFAIR, as to have an analogue to Method > > literals. As the result is a Field instance, chaining does not make > > sense. Literals are only defined on types not instances. > > > > I'm not sure about autoconverting foo#bar to some Property instance. The > > main goal, as far as I understood, is to have compile time checks on > > accessing properties instead of using Strings. Not sure, if this helps, > > but just to note down the thought: > > > > As a prerequisite, we might need a generified Field class (not > > necessarily has to be the java.reflect.Field class). Now assuming Foo > > having a field bar of type Bar, and Bar having a field baz of type Baz. > > Using (generified) Field literals, one could create a property builder > > taking Fields instead of Strings as parameters, e.g.: > > > > Property p1 = PropertyBuilder.on(Foo.class).at(Foo#bar); > > Property p2 = > > PropertyBuilder.on(Foo.class).via(Foo#bar).at(Bar#baz); Property > Bar> p3 = PropertyBuilder.on(foo).at(Foo#bar); > > Property p4 = PropertyBuilder.on(foo).via(Foo#bar).at(Bar#baz); > > > > I admit, this does not look as neat, but would serve the purpose. Or am I > > missing the target? > > > > Cheers, > > Stefan > > Yes it would server the purpose, and frankly ease of use is trumped by > desparate need so I am happy to take any compiler checkable solution > that works. > > In effect the Property class becomes the generified Field object, so that > problem is circumvented. > > The only thing it can not do is to check that the chain is correct (i.e in > the example above that Foo#bar is a Bar( at compile time. When the > PropertyBuilding is building the Property it can, but that is a little > later than I would like - but still a great improvement on evalutation > time, added to which the chained case is a minority case. > > My only question concerns annotations. It is important that the Field > object is the real one, and not a synthetic partial copy. The reason for > this is so that I can access Annotations. If this will work then I am > happy. > > So if FCM is going to be in -7 then my proposal is unnecessary. But of > course that makes an assumption and unless I have missed something it > seemed to be as far off as Property support. > > David As a further thought, I don't suppose there is any chance of changing FCM slightly to have Foo#bar#ali produce a Field array? The simple case can continue to produce a single Field and the PropertyBuilder can have overloaded methods. That would get around the checkability problem. David From david.goodenough at linkchoose.co.uk Fri Mar 6 02:24:10 2009 From: david.goodenough at linkchoose.co.uk (David Goodenough) Date: Fri, 6 Mar 2009 10:24:10 +0000 Subject: PROPOSAL: Lightweight Properties In-Reply-To: <7D2077BFF677D2429DDDEE095D9A48AC105DEECA@osiris2.e-spirit.de> References: <96DF7D6A-C683-4989-955C-D4A90BBC4B54@zwitserloot.com> <200903060947.24239.david.goodenough@linkchoose.co.uk> <7D2077BFF677D2429DDDEE095D9A48AC105DEECA@osiris2.e-spirit.de> Message-ID: <200903061024.11476.david.goodenough@linkchoose.co.uk> On Friday 06 March 2009, Schulz, Stefan wrote: > > In effect the Property class becomes the generified Field > > object, so that > > problem is circumvented. > > Well, the generified Field object should be returned by the reference, so > that the generic type can be retrieved at compile-time, otherwise it would > not make much sense. That's why the example uses the factory method > at(), otherwise it will be difficult to have > compile time type safety. > > > The only thing it can not do is to check that the chain is > > correct (i.e in the > > example above that Foo#bar is a Bar( at compile time. When the > > PropertyBuilding is building the Property it can, but that > > is a little later > > than I would like - but still a great improvement on > > evalutation time, added > > to which the chained case is a minority case. > > You are right. I forgot about the correctness of the chain. And this will > only be possible by a new notation. If the FCM could be extended to produce a Field array if there was a chain that would be a good solution to this problem (see my other response). > > > My only question concerns annotations. It is important that > > the Field object > > is the real one, and not a synthetic partial copy. The > > reason for this is > > so that I can access Annotations. If this will work then I am happy. > > I don't understand this one. You won't annotate the Field class but the > field, so the object returned will have to support Annotation retrieval, I > guess. This concern arised from a problem with PropertyDescriptors. If you get a PropertyDescriptor for a field, and ask for its Type, the Class that is returned is the Class of the return object from the getter rather than the Class of the actual field. This means that you can not get access to any annotations that have been declared on the field. What I was worried about was that this mechanism might construct a Field object, rather than returning the real Field object held in the containing class, and thus be subject to the same problem. Sorry if I was unclear (I may still be unclear). > > > So if FCM is going to be in -7 then my proposal is > > unnecessary. But of course > > that makes an assumption and unless I have missed something it seemed > > to be as far off as Property support. > > FCM won't. But maybe a proposal for Field-Literals might have a chance, as > it seems a coin to me. Not much magic about it, I think. But then again, I > might miss the hard parts as I have no real insight into javac etc. Well I have started to work on that. I hope to have at least a first cut next week although it is making my head ache a bit. On second (or it is third) reading, the documentation I have found is making more sense than it did the previous times. > > @Joe: Would it make sense to file a proposal on Field-Literals or would it > be doomed right away? And I am not sure, whether completing such a proposal > by Method- and Constructor-Literals would become too big for Coin. Any > hint? I would be quite happy to reduce my proposal to just Field Literals. > > Further, I am not sure, how elaborate I could do it by myself, too, so any > coop is welcome. Sorry, for getting off topic. > > Cheers, Stefan David From reinier at zwitserloot.com Fri Mar 6 06:58:06 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 6 Mar 2009 15:58:06 +0100 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: <49B0DEB6.4010308@univ-mlv.fr> References: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> <49B0DEB6.4010308@univ-mlv.fr> Message-ID: The plot thickens. Javac v1.5 WILL warn you when you de-varargs a superclass. However, any javac v1.6 will NOT. Evidently one of the javac engineers had a reason to remove the warning. That reason would probably be very pertinent to this discussion. Anyone familiar enough with mercurial to dig the comment on this changeset out of the javac's repository? Remi - I covered the need to update superclasses without breaking implementers, but if you (re)compile a subclass that de-varargses when source compatibility mode is 1.5 or up, I can see absolutely no reason for javac to be silent about it. It should generate this warning. That change to javac 1.6 needs to be undone. If, as Remi suggests, we treat warnings as effective errors, and thus we treat generics-based arrays as something you really shouldn't ever use, then we have an entirely different bug: The varargs mechanism is then broken. Something as simple as this should then not be something you ever ought to do (eventhough in practice it can't go wrong and the warning generated by the following code snippet is a 'bug' in that there's no way it'll ever break): listOfLists = Arrays.asList(listA, listB); If there is no (acceptible) way to let the compiler figure out what is and isn't safe, then the only solution I can see is to introduce java.lang.VarArgs, and new syntax (4 dots?), or just re-use java.util.List. Either way, I'm still convinced that this is effectively a javac bug, or at the very least a severe 'feature' that has caused many tens of thousands of manhours of solution-hunting and frustration. For what it's worth, its my opinion that we can and should figure out when varargs methods are perfectly safe, generate no warnings anywhere if that happens and all involved code is compiled by javac7 or higher, and accept that Bad Things will happen if you varargs a non-reified type into a method where a subclass has reified the type (but that warning should be restored). After all, Bad Things happen now too, and in either situation you get at least 1 warning. However, in the proposed solution, the warning is at least moved to the place where it is more relevant: The programmer who is reifying that array type. Granted, without an additional proposal to rewrite a signature to Object[], there's nothing this programmer can do about it, but at least he knows what's happening. The current warning on the call site does absolutely nothing useful other than suggesting you can't really use varargs at all, eventhough (quite literally) in 99%+ of all cases, there's absolutely no danger whatsoever. --Reinier Zwitserloot On Mar 6, 2009, at 09:28, R?mi Forax wrote: > Reinier Zwitserloot a ?crit : >> Heh, that was the next proposal I was going to write. >> >> (Apologies for a long and technically complicated post. I've >> rewritten it several times in an attempt to get to the point >> faster, but this is the best I can do). >> >> It really pains me to rain on your parade. I was doing some >> experimenting and found an admittedly very unlikely scenario that >> isn't backwards compatible. Then I realized, that this is actually >> (arguably) a bug, or at least a severe misfeature in javac right >> now! Therefore, this proposal should fix this problem as well. Of >> all proposals so far, I rate this one the highest, because it >> causes so much confusion and is closer to a bug in javac than a >> language feature, so I would be very happy if this proposal can be >> fully ironed out. >> >> Complete code showing the problem - copy and paste into Main.java, >> compile, and run: >> >> ------ >> >> import java.util.*; >> >> class Foo { >> public void foo(T... t) {} >> } >> >> class Bar extends Foo { >> //de-varargsing? Why is this legal? >> > Because you want to be able to replace an array with a varargs in > library without > creating errors in code that use that library. >> public void foo(String[] t) { >> System.out.println(t.getClass().getComponentType()); >> } >> } >> >> public class Main { >> public static void main(String[] args) { >> Foo f = new Bar(); >> List l = Arrays.asList("a", "b", "c"); >> bar(f, l); >> } >> >> public static void bar(Foo f, List l) { >> f.foo(l.get(0), l.get(1), l.get(2)); >> } >> } >> > >> ----- >> >> The result is an error: >> >> Exception in thread "main" java.lang.ClassCastException: >> [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; >> >> Right now, you get the usual varargs warning, but nothing else at >> compile time. At runtime, you get the above error. >> > Warnings in Java are not like in C, it means something will go > wrong :) > > the call: > > f.foo(l.get(0), l.get(1), l.get(2)); > > generate a warning because you are creating an arry of parameterized > type > (a Foo[]) which are "inherently unsafe" to quote gilad bracha. > >> The real bug here is the ability for any subclass to de-varargs a >> parameter. > No > > [...] > > See: >>> Angelika Langer's Java Generics FAQ, "Why does the compiler >>> sometimes issue >>> an unchecked warning when I invoke a 'varargs' method?" ( >>> http://tinyurl.com/8w2dk) >>> > R?mi From reinier at zwitserloot.com Fri Mar 6 07:09:57 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 6 Mar 2009 16:09:57 +0100 Subject: Proposal: Import Aliases for Classes and Static Methods In-Reply-To: References: <49AF1114.3080205@sun.com> <49AF15DC.20408@gmail.com> Message-ID: <76EF2101-0CF8-4CDF-912F-9A36EE2A40C3@zwitserloot.com> package imports would solve all these problems no, and be simpler to boot? My major concern with type aliases is code snippets: When people post a snippet, they almost never include import statements. Many IDEs ship out-of-the-box as collapsing import statements but nothing else. They aren't generally considered important to grok any code snippet. But with type aliases, that changes. Note that anybody casually perusing a complete source file is effectively still 'reading a snippet', so to speak, though at least an IDE can help and e.g. jump to the proper class when ctrl+clicking the type, or showing the complete type in a tooltip. You don't have that problem with package imports. "sql.List" is about as easy to type as "SQLList", and it does not create the inherent confusion in the name that "SQLList" has; I would interpret any type named "SQLList" as "A List contain SQLs, whatever those are". Someone else will need to adapt or rewrite a proposal (my plate is full). Package imports don't help if the only difference in the FQN is near the front, but I don't know of any two commonly used classes together that differ only near the front. (e.g. sunw.io.Serializable vs. java.io.Serializable can't be simplified with package imports, but, nobody uses sunw.*, so not a relevant use case). --Reinier Zwitserloot On Mar 6, 2009, at 05:50, Phil Varner wrote: >> Static import was surprising complicated in JDK 5. While these >> aliases could alleviate some problems, I think they would be easily >> abused >> and even when not being abused render code less readable. >> IMO, having alternate names for potentially common classes would be >> less readable. > > I agree for common classes this could be a problem, but I don't think > it would be any less of a problem than the existing support for > wildcards. I see this more as a solution targeted mostly for long > package names with overlapping class names. I'm going to need to > think some about what "readable" really means, and would be interested > in any thoughts on this topic. > >> While grammar changes are part of the picture, the substantive >> changes would be to JLSv3 section 6.5 "Determining the Meaning of a >> Name": > > Thanks for pointing this out, it's definitely a huge hole in the > proposal. > >> The Javapolis discussions of 2007 ended with the majority of >> participants choosing against aliasing of imports (typedefs). >> >> http://www.javapolis.com/confluence/plugins/advanced/gallery-slideshow.action?pageId=32793&decorator=popup&imageNumber=9 > > Thanks for the pointer. I, too, would probably vote against a the > proposal of > import Map as CodeValueMap; > > Several of the related bugs mention this syntax, but I think this > combines two issues together. It seems to me that the simple mapping > of a fully-qualified class name to a "short" name is separate from the > typedefing of a specifically-parameterized generified type to a short > name. > > --Phil > > -- > > Machines might be interesting, but people are fascinating. -- K.P. > From markmahieu at googlemail.com Fri Mar 6 08:55:49 2009 From: markmahieu at googlemail.com (Mark Mahieu) Date: Fri, 6 Mar 2009 16:55:49 +0000 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: References: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> <49B0DEB6.4010308@univ-mlv.fr> Message-ID: <3B6B416F-B1F8-4D65-810C-B1F8C0032C4A@googlemail.com> Reinier, On 6 Mar 2009, at 14:58, Reinier Zwitserloot wrote: > The plot thickens. Javac v1.5 WILL warn you when you de-varargs a > superclass. However, any javac v1.6 will NOT. Evidently one of the > javac engineers had a reason to remove the warning. That reason would > probably be very pertinent to this discussion. Anyone familiar enough > with mercurial to dig the comment on this changeset out of the javac's > repository? > is this what you're looking for? http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5048776 Regards, Mark From reinier at zwitserloot.com Fri Mar 6 11:20:02 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 6 Mar 2009 20:20:02 +0100 Subject: PROPOSAL: Simplified Varargs Method Invocation In-Reply-To: <3B6B416F-B1F8-4D65-810C-B1F8C0032C4A@googlemail.com> References: <1782F7B0-2747-4D28-998B-929D0733291D@zwitserloot.com> <49B0DEB6.4010308@univ-mlv.fr> <3B6B416F-B1F8-4D65-810C-B1F8C0032C4A@googlemail.com> Message-ID: <8A06B6EA-DC3B-46D8-AE6E-4321E7055AAD@zwitserloot.com> Mark, good find. It turns out that you can use varargs to invoke a method with signature: public void methodName(Foobar[] x) {} *IF* any supertype of the type containing this method has the same method with varargs. I assume that's why the warning was removed. This magic varargs behaviour is present in both javac 1.5 and javac 1.6. --Reinier Zwitserloot On Mar 6, 2009, at 17:55, Mark Mahieu wrote: > Reinier, > > On 6 Mar 2009, at 14:58, Reinier Zwitserloot wrote: > >> The p